2014-11-20 3 views
0

Я ударил некоторые запутанные сообщения об ошибках от компилятора Swift ('A' is not convertible to 'A', 'E' is not identical to 'E'), и я думаю, что это связано с тем, что я вводил идентичные имена переменных типа в двух областях, где одна область была вложена внутри другой.Какова область переменных типа?

Я хотел бы получить более полное представление о том, как работают переменные типа, и поэтому у меня есть несколько взаимосвязанных вопросов:

  • что объем переменных типа в Swift?
  • ow - это область, на которую влияют вложенные типы и методы?
  • Может ли тип переменных затенять?
  • Что происходит, когда вложенный метод вводит переменную типа с тем же именем, что и класс-оболочка?
  • возможно ли что-то вроде method2 (см. Ниже)? (Мой XCode терпел крах, и я не был в состоянии понять это)

Вот несколько примеров, чтобы показать, что я пытаюсь выяснить:

class MyClass<A> { 

    func method1<A>(a:A) -> A { 
     // what does A refer to here? 
     return a; 
    } 

    class func staticmethod<A>(a:A) -> A { 
     // what does A refer to here? 
     return a; 
    } 

    func method2() -> ((A) -> A) { 
     // is this even possible? 
     // I'm not sure how to write method2's type ! 
     func id<A>(a:A) -> A { 
      return a; 
     } 
     return id; 
    } 

} 

ответ

0

сферу охвата родовых Тип общего класса/структуры/метода/функции - это точно класс/struct/method/function. И да, это может быть затенено вложенными определениями.

В вашем примере A в method1 является общим типом для этого метода и при вызове метода будет заменен фактическим типом . Он тени общий типа MyClass<A>. Пример:

let mc = MyClass<Int>()  // class instantiated with actual type Int 
let x = mc.method1("foo") // method called with actual type String 
println(x) // "foo" 

То же самое относится и к статическим методом:

let y = MyClass<Int>.staticmethod(123.5) // method called with type Double 
println(y) 

В вашем method2, внутренняя функция не получает параметр типа, он должен быть (и я удалил одну пару от ненужных скобок):

func method2a() -> (A) -> A { 
    func id(a:A) -> A { 
     return a; 
    } 
    return id; 
} 

или

func method2b<A>() -> (A) -> A { 
    func id(a:A) -> A { 
     return a; 
    } 
    return id; 
} 

в зависимости от того, работает ли он с типом класса или вводит собственный общий тип . Обратите внимание, что вы можете сократить это, используя закрытие вместо вложенной функции , например.

func method2b<A>() -> (A) -> A { 
    return { a in a } 
} 

В первом случае вы будете использовать его как

let mc = MyClass<Int>() // class instantiated with type Int, therefore 
let z = mc.method2a()(12) // mc.method2a() has signature Int -> Int 
println(z) 

и во втором случае вы могли бы сделать

let mc = MyClass<Int>() // class instantiated with type Int, but 
let z = mc.method2b()("bar") // mc.method2b() has signature String -> String 
println(z) 

Здесь фактический тип method2b<A> выводится из аргументов " бар "как String.

Вообще, я бы предпочел использовать разные имена для вложенных генерических типов , чтобы избежать ненужной путаницы.