Что означают A.Type и A.self, где A — некий класс, в языке Swift?

Что означают A.Type и A.self, где A - некий класс, в языке Swift?
  • Вопрос задан
  • 1950 просмотров
Решения вопроса 2
Для любого типа T, T.Type - это метатип (metatype), то есть тип, объекты которого предоставляют описание типа T. Статические функции и init-функции T становятся функциями-членами T.Type. Пример:

struct Duck {
    static func kind() -> String { return "Bird" }
    init() { }
    func talk() { print("Quack") }
}

let meta: Duck.Type = Duck.self
meta.kind()  //=> Bird
let obj: Duck = meta.init()
obj.talk()  //=> Quack


Существует 2 класса метатипов, но на практике встречаются existential metatypes, то есть их объекты могут описывать как данный тип T, так и любой наследник (subtype) типа T. Другими словами, множество объектов типа T.Type - это U.self для всех типов U: T. Пример:

class Animal { class var name: String { return "Animal" } }
class Cat: Animal { override class var name: String { return "Cat" } }
class Dog: Animal { override class var name: String { return "Dog" } }

var meta: Animal.Type
meta = Cat.self
meta.name  //=> Cat
meta = Dog.self
meta.name  //=> Dog


Или, например, можно представить себе такую функцию генерации животных:

class Animal { ... }

func createAnimal(_ type: Animal.Type) -> Animal {
    if type == Cat.self {
        return Cat(...)
    } else if type == Dog.self {
        return Dog(...)
    } else {
        fatalError()
    }
}


На практике, такая функциональность метатипов используется редко. Как правило, они служат для явной специализации шаблонных функций. Например:

func unsafeCast<T, U>(_: T, to: U.Type) -> U

Здесь единственный способ указать тип U при вызове - это передать "фиктивный" параметр тип U.Type, так как аргументов типа U функция не принимает. Вернее, это лучший и принятый в Swift способ. Можно было бы выкрутиться вот так:

func unsafeCast<T, U>(_: T, sameAs: U) -> U

Но, понятно, что для этого нужно иметь под рукой объект типа U, и это не идеальный вариант. Жаль, что нельзя писать просто unsafeCast<U>(t) при вызове.

При использовании метатипа U.Type таким образом, его значение, как правило, игнорируется. То есть даже если вы передадите туда метатип наследника типа U, то функция всё равно будет работать с U.

P.S. Есть ещё много недокументированных фич метатипов в Swift, но там всё не очень логично и продуманно (даже разработчики из Core team не всё там понимают), так что на практике лучше ограничиться применением для явной специализации функций, как показано выше.
Ответ написан
tikhonov666
@tikhonov666
iOS, Swift, Objective-C
Вот пример

class Person {
    var name: String
     required init(name: String) {
        self.name = name
    }
}

func printPersonName(PersonType: Person.Type) {
    // PersonType - Person.Type
    let person = PersonType.init(name: "Name")
    print(person.name)
}

let PersonType = Person.self // Person.Type
printPersonName(PersonType: PersonType)


A.Type - используется для указания типа переменной в сигнатуре функции.
A.self - используется непосредственно в коде как обычная переменная.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы