Swift nil 任何 != nil

Erh*_*nis 1 null ios swift

斯威夫特 5.1。考虑以下。

let x: Any? = nil
let y: Any = x
print("x \(x)")                      // x nil
print("type(of: x) \(type(of: x))")  // type(of: x) Optional<Any>
print("x == nil \(x == nil)")        // x == nil true
print("y \(y)")                      // y nil
print("type(of: y) \(type(of: y))")  // type(of: y) Optional<Any>
print("y == nil \(y == nil)")        // y == nil false
Run Code Online (Sandbox Code Playgroud)

我们有两个变量,设置为相同的东西——nil。他们打印相同,他们的类型打印相同 - 但一个== nil和另一个没有。

  1. 为什么?
  2. 鉴于这样的Any,人们怎么会发现它实际上为零?

Ale*_*ica 6

想想AnyOptional<Wrapped>喜欢盒子。

  1. Any是一个不透明的盒子,可以装任何东西。您可以通过尝试使用as?.
  2. Optional<Wrapped>是一个透明的盒子。它可以让你看到它的内容均是一个价值Optional<Wrapped>.some(wrapped)Optional<Wrapped>.none()

AnOptional<Any>Any包含 anOptional<Wrapped>不是一回事。

1. x

是 的值Optional<Any>.none,也就是nilnil被打印出来,所以这是有道理的。

2. type(of: x)

是的类型xOptional<Any>如我们的预期。

3. x == nil

正在调用==类型为 的运算符(T, T) -> Bool。由于两个 args 都需要是相同的类型,并且x具有Optional<Any>.none(类型Optional<Any>)的值,nil因此推断为Optional<Any>.none。两者是等价的,所以我们得到了true,正如预期的那样。

4. y

是一个类型的值Any。在编译时,对y. 恰巧隐藏在不透明窗帘背后的价值Anyxprint实现“透视” Any instances,向您展示真正存在的东西。

5. type(of: y)

正在做类似的事情print。它使用运行时类型信息来准确查看存储的运行时值是什么yyis的静态类型Any,但type(of: y)向我们展示了其值的运行时类型是Optional<Any>

6. y == nil

这是它变得有点棘手的地方。

选择调用哪个函数或运算符的重载是在编译时完成的,基于操作数的静态已知类型。也就是说,操作符和函数不是根据它们的参数类型动态调度的,而是基于它们的对象类型(例如fooin foo.bar())动态调度的。

此处选择的重载是==(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool。您可以在 的第 449-481 行Optional.swift看到它的实现。

它的左侧操作数是Wrapped?,又名Optional<Wrapped>

它的右侧操作数是_OptionalNilComparisonType。这是一种特殊类型,符合ExpressibleByNilLiteral.

Optional 是一种符合的类型ExpressibleByNilLiteral,这意味着您可以编写let x: Optional<Int> = nil,并且编译器可以使用该协议来理解nil应该意味着什么Optional<Int>.none。该ExpressibleByNilLiteral协议的存在允许此行为可以被其他类型扩展。例如,您可以想象一个 Python 互操作性框架,您希望能够在其中说let none: PyObject = nil, 可以传递到Python 的 null 类型Python并解析为None

这里发生的事情是左侧(y, 类型Any)被提升为类型Any?。提升的值具有类型Optional<Any>.some(old_value_of_y)。右侧的nil用于实例化 的值_OptionalNilComparisonType,相当于调用_OptionalNilComparisonType.init(nilLiteral: ())

因此,您的呼叫站点相当于:

Optional<Any>.some((Optional<Any>.none) as Any) == _OptionalNilComparisonType(nilLiteral: ()) /*
?                  ???_the value of x_??       ??
?                  ??_the value of y _________???
??_the value of y after promotion to optional__?? */
Run Code Online (Sandbox Code Playgroud)

根据实现,左侧是 a some,右侧是 a nil,因此它们是不相等的。

你可能会说:

嗯,这是非常不明显的行为,这不是我想要的。

我会回应:

不要忽略编译器错误,它们是正确的:

警告:比较型的非可选值Anynil总是返回false