任何?不正确的语义
Any? incorect semantics
我在研究 swift 中的一些代码时遇到了一个有趣的案例。
让我们从一个小序言开始:假设您创建了一些可选变量:
let a: String? = "abcd"; let b: Int? = 4
print(
"Type of \(a) is \(type(of: a))" //Type of Optional("abcd") is Optional<String>
"Type of \(b) is \(type(of: b))", //Type of Optional(4) is Optional<Int>
separator: "\n"
)
然后你强制解包,所以 au
和 bu
类型不是可选的。
let au = a!; let bu = b!
print(
"Type of \(au) is \(type(of: au))", //Type of abcd is String
"Type of \(bu) is \(type(of: bu))", //Type of 4 is Int
au + String(bu), //abcd4
separator: "\n"
)
看似合理,但当您尝试将相同的代码应用于 Optional<Any>
:
时,事情开始变得奇怪
let a: Any? = "abcd"; let b: Any? = 4
let au = a!; let bu = b!
print(
"Type of \(a) is \(type(of: a))", //Type of Optional("abcd") is Optional<Any>
"Type of \(b) is \(type(of: b))", //Type of Optional(4) is Optional<Any>
"Type of \(au) is \(type(of: au))", //Type of abcd is String
"Type of \(bu) is \(type(of: bu))", //Type of 4 is Int
//au + String(bu),
separator: "\n"
)
但是现在,如果您尝试进行相同的串联 au + String(bu)
,swift 将产生编译错误,即使这两个变量已知属于某种具体类型,如 [= 所报告的那样28=] 本身。
错误是:
error: protocol type 'Any' cannot conform to 'LosslessStringConvertible' because only concrete types can conform to protocols
这看起来确实像一个错误,不是吗。请分享您的意见。
type(of: T) 方法获取任何变量的运行时类型。这就是为什么你看到 (type(of: au) as String。但是 Swift 出于安全原因不允许隐式类型转换。这就是你不能添加 Int 和 Double 而不在 [=12= 中进行转换的原因]。您需要显式转换才能使您的代码正常工作。
type(of: T)
Returns 值的动态类型。
您可以使用 type(of:)
函数来查找值的动态类型,
特别是当动态类型不同于静态类型时。这
值的 static 类型 是该值的已知编译时类型。这
值的 动态类型 是值在 运行 时的实际类型,即
可以是其具体类型的子类型。
此解释摘自 type(of: T)
函数上方的注释。按 Cmd 并单击 Xcode 中的 type(of: T)
阅读更多内容
正如其他人所指出的,type(of:)
是值的动态运行时类型。编译器仅依赖于值的静态、可证明类型。在上面的代码中,编译器唯一可以证明的是 au
将是 Any 类型。符合 Any 的众多类型之一是 String,但编译器不知道在所有可能的代码路径中,该值确实是一个 String。
由于没有 func + (Any, String)
重载,因此无法编译。
请注意,Any?
是一种奇怪而危险的类型。它的问题不是这个例子的原因,但它与 Optional 提升交互的方式可能会导致明显的歧义和混淆。 Swift 中的每种类型都可以隐式提升为该类型的 Optional。 Swift 中的每个类型都可以隐式转换为 Any。结合这两个事实意味着 Any
可以隐式提升为 Any?
,或 Any??
,或 Any???
,等等,但所有这些也是 [= 的子类型14=]。这会造成各种微妙的头痛。你应该强烈避免使用 Any
;它很少是正确的工具。但是您应该更加小心地允许 Any?
出现在您的代码中。这表明可能出了问题。
我在研究 swift 中的一些代码时遇到了一个有趣的案例。 让我们从一个小序言开始:假设您创建了一些可选变量:
let a: String? = "abcd"; let b: Int? = 4
print(
"Type of \(a) is \(type(of: a))" //Type of Optional("abcd") is Optional<String>
"Type of \(b) is \(type(of: b))", //Type of Optional(4) is Optional<Int>
separator: "\n"
)
然后你强制解包,所以 au
和 bu
类型不是可选的。
let au = a!; let bu = b!
print(
"Type of \(au) is \(type(of: au))", //Type of abcd is String
"Type of \(bu) is \(type(of: bu))", //Type of 4 is Int
au + String(bu), //abcd4
separator: "\n"
)
看似合理,但当您尝试将相同的代码应用于 Optional<Any>
:
let a: Any? = "abcd"; let b: Any? = 4
let au = a!; let bu = b!
print(
"Type of \(a) is \(type(of: a))", //Type of Optional("abcd") is Optional<Any>
"Type of \(b) is \(type(of: b))", //Type of Optional(4) is Optional<Any>
"Type of \(au) is \(type(of: au))", //Type of abcd is String
"Type of \(bu) is \(type(of: bu))", //Type of 4 is Int
//au + String(bu),
separator: "\n"
)
但是现在,如果您尝试进行相同的串联 au + String(bu)
,swift 将产生编译错误,即使这两个变量已知属于某种具体类型,如 [= 所报告的那样28=] 本身。
错误是:
error: protocol type 'Any' cannot conform to 'LosslessStringConvertible' because only concrete types can conform to protocols
这看起来确实像一个错误,不是吗。请分享您的意见。
type(of: T) 方法获取任何变量的运行时类型。这就是为什么你看到 (type(of: au) as String。但是 Swift 出于安全原因不允许隐式类型转换。这就是你不能添加 Int 和 Double 而不在 [=12= 中进行转换的原因]。您需要显式转换才能使您的代码正常工作。
type(of: T)
Returns 值的动态类型。
您可以使用 type(of:)
函数来查找值的动态类型,
特别是当动态类型不同于静态类型时。这
值的 static 类型 是该值的已知编译时类型。这
值的 动态类型 是值在 运行 时的实际类型,即
可以是其具体类型的子类型。
此解释摘自 type(of: T)
函数上方的注释。按 Cmd 并单击 Xcode 中的 type(of: T)
阅读更多内容
正如其他人所指出的,type(of:)
是值的动态运行时类型。编译器仅依赖于值的静态、可证明类型。在上面的代码中,编译器唯一可以证明的是 au
将是 Any 类型。符合 Any 的众多类型之一是 String,但编译器不知道在所有可能的代码路径中,该值确实是一个 String。
由于没有 func + (Any, String)
重载,因此无法编译。
请注意,Any?
是一种奇怪而危险的类型。它的问题不是这个例子的原因,但它与 Optional 提升交互的方式可能会导致明显的歧义和混淆。 Swift 中的每种类型都可以隐式提升为该类型的 Optional。 Swift 中的每个类型都可以隐式转换为 Any。结合这两个事实意味着 Any
可以隐式提升为 Any?
,或 Any??
,或 Any???
,等等,但所有这些也是 [= 的子类型14=]。这会造成各种微妙的头痛。你应该强烈避免使用 Any
;它很少是正确的工具。但是您应该更加小心地允许 Any?
出现在您的代码中。这表明可能出了问题。