在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
吗?
使用Xcode Playground 7.2 + Swift 2.1.1进行测试
Cristik.. 66
TL; DR; swift中的Optionals由编译器转换为Optional
枚举实例,因为Any
可以映射到任何值,它可以用于存储选项.
Swift如何代表选项?它通过映射SomeType?
到Optional
枚举的具体实现来实现:
Int? => OptionalString? => Optional
这样的简化声明Optional
:
enum Optional{ case none // nil case some(T) // non-nil }
现在,类型的变量Any
能够保存枚举值(或任何其他类型的值,甚至是元类型信息),因此它应该能够保存例如nil
String,aka String?.none
,aka Optional
.
让我们看看会发生什么.正如我们在Optional
声明中看到的那样,nil
对应.none
于所有类型的枚举案例:
nil == Optional.none // true nil == Optional .none // true [Double]?.none == nil // also true
所以理论上,你应该能够分配nil
一个声明为的变量Any
.但是,编译器不允许这样做.
但为什么编译器不允许您分配nil
给Any
变量?这是因为它无法推断映射.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.none
,因为上面的Any
变量实际上是持有Optional
枚举的有效值.
间接分配也可以,因为幕后nil
转换为Optional
.
var nilableBool: Bool? // nilableBool has the Optional.none value var nilBoolAsAny: Any = nilableBool // the compiler has all the needed type information from nilableBool
与其他语言不同,Swift nil
对应于具体的值.但它需要一种类型才能使用,以便编译器知道Optional
应该分配哪种类型.我们可以将关键字视为提供糖语法.
TL; DR; swift中的Optionals由编译器转换为Optional
枚举实例,因为Any
可以映射到任何值,它可以用于存储选项.
Swift如何代表选项?它通过映射SomeType?
到Optional
枚举的具体实现来实现:
Int? => OptionalString? => Optional
这样的简化声明Optional
:
enum Optional{ case none // nil case some(T) // non-nil }
现在,类型的变量Any
能够保存枚举值(或任何其他类型的值,甚至是元类型信息),因此它应该能够保存例如nil
String,aka String?.none
,aka Optional
.
让我们看看会发生什么.正如我们在Optional
声明中看到的那样,nil
对应.none
于所有类型的枚举案例:
nil == Optional.none // true nil == Optional .none // true [Double]?.none == nil // also true
所以理论上,你应该能够分配nil
一个声明为的变量Any
.但是,编译器不允许这样做.
但为什么编译器不允许您分配nil
给Any
变量?这是因为它无法推断映射.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.none
,因为上面的Any
变量实际上是持有Optional
枚举的有效值.
间接分配也可以,因为幕后nil
转换为Optional
.
var nilableBool: Bool? // nilableBool has the Optional.none value var nilBoolAsAny: Any = nilableBool // the compiler has all the needed type information from nilableBool
与其他语言不同,Swift nil
对应于具体的值.但它需要一种类型才能使用,以便编译器知道Optional
应该分配哪种类型.我们可以将关键字视为提供糖语法.
来自Swift Docs:" Any
:所有类型都隐含符合的协议."
即 typealias Any = protocol<>
因此,当您声明时String?
,您可以将其视为Optional
,在哪里Optional
可以实现为:
enum Optional{ case Some(T), None }
枚举是类型,因此它们符合Any
协议.如评论中所述,nil
不是类型(因此不符合Any
,它是没有值(在这种情况下,没有值没有类型).
可选项被烘焙到语言中,并不是常规枚举,但它仍然表示它们符合,Any
而无类型nil
则不符合.