Here is a quick example:
func printType<T>(of type: T.Type) {
// or you could do "(T.self)" directly and
// replace `type` parameter with an underscore
print("(type)")
}
printType(of: Int.self) // this should print Swift.Int
func printInstanceDescription<T>(of instance: T) {
print("(instance)")
}
printInstanceDescription(of: 42) // this should print 42
Let's say that each entity is represented by two things:
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
Source.
You can quickly notice that this is recursive and there can by types like (((T.Type).Type).Type)
and so on.
.Type
returns an instance of a metatype.
There are two ways we can get an instance of a metatype:
Dangerous area:
struct S {}
protocol P {}
print("(type(of: S.self))") // S.Type
print("(type(of: S.Type.self))") // S.Type.Type
print("(type(of: P.self))") // P.Protocol
print("(type(of: P.Type.self))") // P.Type.Protocol
.Protocol
is yet another metatype which only exisits in context of protocols. That said, there is no way how we can express that we want only P.Type
. This prevents all generic algorithms to work with protocol metatypes and can lead to runtime crashes.
For more curious people:
The type(of:)
function is actually handled by the compiler because of the inconsistency .Protocol
creates.
// This implementation is never used, since calls to `Swift.type(of:)` are
// resolved as a special case by the type checker.
public func type<T, Metatype>(of value: T) -> Metatype { ... }
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…