Для любого типа
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 не всё там понимают), так что на практике лучше ограничиться применением для явной специализации функций, как показано выше.