为什么非可选的Any可以保持nil? [英] Why non optional Any can hold nil?
问题描述
在Swift中,我可以声明类型为Any
的常量,并在其中放入String
.
In Swift I can declare a constant of type Any
and put a String
into it.
let any: Any = "hello world"
好.另一方面,我不能将nil
值放入any
,因为它不是可选的.
Good. On the other hand I cannot put a nil
value into any
because it's not optional.
let any: Any = nil
error: nil cannot initialize specified type 'Any' (aka 'protocol<>')
let any: Any = nil
^
完美.但是为什么编译器允许我编写以下代码?
Perfect. But why does the compiler allow me do write the following code?
let couldBeNil: String? = nil
let any: Any = couldBeNil
print(any) // nil
Any
是否不遵循Swift规则,即只能用nil
填充可选的var/let?
Doesn't Any
follow the Swift rule that only an Optional var/let can be populated with nil
?
在Xcode Playground 7.2 + Swift 2.1.1中进行了测试
Tested with Xcode Playground 7.2 + Swift 2.1.1
推荐答案
TL; DR; 编译器将swift中的可选内容翻译为Optional
枚举实例,并且由于Any
可以映射设置为任意值,可用于存储可选内容.
TL;DR; Optionals in swift are translated by the compiler to Optional
enum instances, and since Any
can map to any value, it can be used to store optionals.
Swift如何表示可选内容?通过将SomeType?
映射到Optional
枚举的具体实现来实现:
How does Swift represent optionals? It does it by mapping SomeType?
to a concrete implementation of the Optional
enum:
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
.
Now, a variable of type Any
is able to hold an enum value (or any other kind of value, or even metatype information), so it should be able to hold for example a nil
String, aka String?.none
, aka Optional<String>.none
.
让我们看看会发生什么.正如我们在Optional
声明中看到的,nil
对应于所有类型的.none
枚举大小写:
Let's see what happens, though. As we see by the Optional
declaration, nil
corresponds to the .none
enum case for all types:
nil == Optional<String>.none // true
nil == Optional<Int>.none // true
[Double]?.none == nil // also true
因此,从理论上讲,您应该能够将nil
分配给声明为Any
的变量.尽管如此,编译器仍不允许这样做.
So theoretically, you should be able to assign nil
to a variable declared as Any
. Still, the compiler doesn't allow this.
但是为什么编译器不让您将nil
分配给Any
变量?这是因为它无法推断映射.none
枚举大小写的类型. Optional
是一个通用枚举,因此它需要一些内容来填充T
通用参数,而普通的nil
太宽了.应该使用哪个.none
值?来自Int
的一个,来自String
的一个,另一个??
But why doesn't the compiler let you assign nil
to an Any
variable? It's because it can't infer to which type to map the .none
enum case. Optional
is a generic enum, thus it needs something to fill the T
generic parameter, and plain nil
is too broad. Which .none
value should it use? The one from Int
, the one from String
, another one?
这会给出一条支持以上段落的错误消息:
This gives an error message supporting the above paragraph:
let nilAny: Any = nil // error: nil cannot initialize specified type 'Any' (aka 'protocol<>')
以下代码有效,并且等效于分配nil
:
The following code works, and is equivalent to assigning a nil
:
let nilAny: Any = Optional<Int>.none
,因为上面的Any
变量实际上保存了Optional
枚举的有效值.
, as the above Any
variable is actually holding a valid value of the Optional
enum.
间接分配也起作用,因为nil
在后台被转换为Optional<Type>.none
.
Indirect assignments work too, as behind the scenes nil
is converted to 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
.我们可以认为该关键字提供了糖语法.
Unlike other languages, in Swift nil
corresponds to a concrete value. But it needs a type to work with, for the compiler to know which Optional<T>.none
it should allocate. We can think of the keyword as providing sugar syntax.
这篇关于为什么非可选的Any可以保持nil?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!