-
概述
type(of:) 用于获取值的动态类型,动态类型指的是元类型(MetaType)的值
func printInfo(_ value: Any) {
let t = type(of: value)
print("'\(value)' of type '\(t)'")
}
let integer: Any = 5 // integer的静态类型为Any
printInfo(integer) //'5' of type 'Int'
// integer的动态类型为Int
上述例子中integer的静态类型和动态类型并不一样,type(of:) 返回的是integer在运行时的类型
type(of:) 返回的动态类型可以是class, structure, enumeration 的 concrete metatypes (T.Type),也可以是 protocol, protocol composition 的 existential metatype (P.Type),如果 type(of:) 的参数的静态类型是 class 或者实现了 protocol,可以使用其返回的动态类型访问 class 或 protocol 中定义的构造函数或静态成员
class Smiley {
class var text: String {
return ":)"
}
}
class EmojiSmiley : Smiley {
override class var text: String {
return "😀"
}
}
func printSmileyInfo(_ value: Smiley) {
let smileyType = type(of: value)
print("Smile!", smileyType.text)
}
let emojiSmiley = EmojiSmiley()
printSmileyInfo(emojiSmiley)
// Smile! 😀
上述例子中,emojiSmiley的动态类型为EmojiSmiley,所以访问 type(of:) 返回的动态类型中的静态成员得到的是 😀,而不是 :)
-
type(of:)在泛型上下文中的坑!
func printGenericInfo<T>(_ value: T) {
let t = type(of: value)
print("'\(value)' of type '\(t)'")
}
protocol P {}
extension String: P {}
let stringAsP: P = "Hello!"
printGenericInfo(stringAsP)
// 'Hello!' of type 'P'
上述代码的目的是获取 stringAsP 的动态类型 P.Type,即 String.self,但结果却是 P.Protocol,为什么呢?
这是因为 printGenericInfo<T>(:) 并没有约束泛型参数T是实现了协议P的类型,而 stringAsP 的静态类型是P,所以将 stringAsP 传入 printGenericInfo<T>(:) 会让编译器认为传入的参数是一个protocol而不是一个实现了protocol的类型,所以 type(of:) 只能返回该protocol的动态类型,即 P.Protocol,而不是 P.Type
如果需要在泛型上下文中获取传入值的动态类型,需要先将传入值转换成 Any
func betterPrintGenericInfo<T>(_ value: T) {
let t = type(of: value as Any)
print("'\(value)' of type '\(t)'")
}
betterPrintGenericInfo(stringAsP)
// 'Hello!' of type 'String'
关于 Metatype, concrete metatypes, existential metatype 的解读可以看看: Swift -- MetaType
-
参考文献: