任何?不正确的语义

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"
)

然后你强制解包,所以 aubu 类型不是可选的。

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? 出现在您的代码中。这表明可能出了问题。