这种行为实际上一点也不奇怪,如果您了解 Swift 字典和可选项的一些基本特性,这是一个非常自然的结果。
嵌套选项
首先,可选项是可组合的。你可以有嵌套的选项,比如Optional<Optional<Int>>(又名Int??)。像这样的嵌套选项可能有三个值。为了说明它们的区别,想象一下array.first的结果,其中array的类型为Array<Optional<Optional<Int>>:
Optional.some(Optional.some(someWrappedValue)),这只是“非零”情况,有效载荷为someWrappedValue。在array.first 的上下文中,这意味着数组是非空的,并且第一个元素是非零值someWrappedValue(Int 类型)。
Optional.some(Optional.none),这是一个包含nil 的非零可选。在array.first的上下文中,这意味着十个数组是非空的,第一个元素本身就是nil。
Optional.none,这只是一个nil 可选。在array.first 的上下文中,这意味着数组是空的,并且没有第一个元素。
请注意案例 2 和案例 3 之间的区别。沿链“找到” nil 的“位置”具有语义差异。 Optional.none (a.k.a. nil) 表示没有元素,这在语义上与 Optional.some(Optional.none) 不同,这意味着有 are 个元素,但其中第一个实际上是 nil。
nil的确切含义
其次,nil 是Optional<T>.none 的简写,其中T 是从上下文中推断出来的。例如,这就是为什么let x = nil 是非法的,因为类型推断系统不知道T 的什么值是合适的。
请注意,nil 本身被推断为处于“最早”(“最外层”)可选级别的 none。 (案例3,在上面的列表中)
通过字典下标分配 nil
第三,通过下标将nil 分配给字典会删除给定键的值。
把它放在一起
鉴于这三点,我们可以考虑您的示例。字典的下标比字典的Value 泛型类型“多一层可选”。例如。对于[Int: Int]类型的dict,下标运算符的返回类型为V?,对应的可以赋值Int?。
现在考虑你的字典,类型为[Int: Int?]。下标接受/返回Int??。让我们像以前一样在上下文中考虑三种可能的情况:
分配Optional.some(Optional.some(someWrappedValue)) 类型的值会使dict 为键存储someWrappedValue 的值,作为Int?。这就是你写$0[$1] = 1 时发生的事情(Swift 隐含地将1 提升为Optional.some(Optional.some(1))。
分配 Optional.some(Optional.none) 类型的值会使 dict 为键存储 nil 的值,作为 Int?。这是您缺少的部分。
分配 Optional.none 类型的值会使 dict 删除键可能存在的任何值。这就是你写$0[$1] = nil
时发生的事情
因此,要使此代码给出您设计的结果,您需要提供第二种类型的值。你可以这样做:
[1,2,3].reduce(into: [Int:Int?]()) { $0[$1] = Optional.some(nil) }