swift - 为什么非可选的 Any 可以容纳 nil?

标签 swift option-type

在 Swift 中,我可以声明一个类型为 Any 的常量,然后将一个 String 放入其中。

let any: Any = "hello world"

很好。另一方面,我不能nil 值放入any,因为它不是可选的。

let any: Any = nil

error: nil cannot initialize specified type 'Any' (aka 'protocol<>')
let any: Any = nil
              ^

完美。但是为什么编译器允许我写下面的代码呢?

let couldBeNil: String? = nil
let any: Any = couldBeNil
print(any) // nil

难道 Any 不遵循 Swift 规则,即只有 Optional var/let 可以用 nil 填充吗?

Tested with Xcode Playground 7.2 + Swift 2.1.1

最佳答案

TL;DR; swift 中的可选项被编译器翻译成 Optional枚举实例,并且自 Any可以映射到任何值,它可以用来存储可选值。


Swift 如何表示可选值?它通过映射 SomeType? 来实现Optional的具体实现枚举:

Int? => Optional<Int>
String? => Optional<String>

Optional 的简化声明看起来像这样:

enum Optional<T> {
    case none    // nil
    case some(T) // non-nil
}

现在,一个类型为 Any 的变量能够保存枚举值(或任何其他类型的值,甚至是元类型信息),因此它应该能够保存例如 nil。字符串,又名 String?.none , 又名 Optional<String>.none .

不过,让我们看看会发生什么。正如我们所看到的 Optional声明,nil对应于.none所有类型的枚举大小写:

nil == Optional<String>.none // true
nil == Optional<Int>.none    // true
[Double]?.none == nil        // also true

所以理论上,您应该能够分配 nil声明为 Any 的变量.不过,编译器不允许这样做。

但是为什么编译器不让你分配nilAny多变的?这是因为它无法推断将 .none 映射到哪种类型枚举案例。 Optional是一个通用枚举,因此它需要一些东西来填充 T通用参数和普通参数 nil太宽泛了。哪个.none它应该使用的值?来自 Int 的那个, 来自 String 的那个,另一个?

这给出了支持以上段落的错误消息:

let nilAny: Any = nil // error: nil cannot initialize specified type 'Any' (aka 'protocol<>')

下面的代码有效,相当于分配一个 nil :

let nilAny: Any = Optional<Int>.none

,如上Any变量实际上持有 Optional 的有效值枚举。

间接赋值也有效,在幕后nil转换为 Optional<Type>.none .

var nilableBool: Bool? // nilableBool has the Optional<Bool>.none value
var nilBoolAsAny: Any = nilableBool // the compiler has all the needed type information from nilableBool

与其他语言不同,在 Swift 中 nil对应一个具体值。但它需要一个类型来工作,让编译器知道哪个 Optional<T>.none它应该分配。我们可以将关键字视为提供糖语法。

关于swift - 为什么非可选的 Any 可以容纳 nil?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34644128/

相关文章:

ios - 如何限制文本字段只能输入十进制数字?

swift - vapor 无法加载 html 和 leaf

Java 可选<List<T>> 到 Map 转换

Java api 返回可选

ios - 有没有办法将我的 `scrollView` 从我的主类连接或访问到另一个类?

swift - 测试 UIImagePicker

swift - ARSCNView 中像素的颜色

swift - if nil != optional ... 和 if let _ = optional ... 之间有什么区别?

Swift 可选转义闭包参数

swift - 展平并展开二维数组中的选项