为什么非可选任何可以保持零?

时间:2016-01-06 22:32:32

标签: swift optional

在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规则,只有nil填充了一个可选的var / let吗?

  

使用Xcode Playground 7.2 + Swift 2.1.1进行测试

3 个答案:

答案 0 :(得分:61)

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的变量。尽管如此,编译器仍然不允许这样做。

但为什么编译器不允许您将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<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。我们可以将关键字视为提供糖语法。

答案 1 :(得分:8)

来自Swift Docs:&#34; Any:所有类型都隐式符合的协议。&#34;

即。 typealias Any = protocol<>

因此,当您声明String?时,您可以将其视为Optional<String>,其中Optional<T>可以实现为:

enum Optional<T> {
  case Some(T), None
}

枚举是类型,因此它们符合Any协议。正如评论中所述,nil不是一个类型(因此不符合Any,它缺少一个值(在这种情况下,没有值没有类型)。

选项会被烘焙到语言中,并不是常规枚举,但它仍然表示它们符合Any而无类型nil则不符合#Persistent SetTitleMatchMode, 2 GroupAdd, Amazon_Apple_Group, Amazon.com ahk_exe firefox.exe GroupAdd, Amazon_Apple_Group, Amazon.com ahk_exe chrome.exe GroupAdd, Amazon_Apple_Group, Apple - Mozilla Firefox ahk_exe firefox.exe GroupAdd, Amazon_Apple_Group, Apple - Google Chrome ahk_exe chrome.exe Gui, Add, Button, w200 h25 gTest1, button 1 Gui, Add, Button, w200 h25 gTest2, button 2 SetTimer, Show_Gui, 300 Return Show_Gui: IfWinActive, ahk_group Amazon_Apple_Group { SetTimer, Show_Gui, Off Gui, Show, NoActivate, foo WinSet, AlwaysOnTop, On, foo ahk_class AutoHotkeyGUI WinWaitNotActive, ahk_group Amazon_Apple_Group Sleep, 50 Gui, Cancel SetTimer, Show_Gui, On } Return Test1: Gui, Submit ; do sth Return Test2: Gui, Submit ; do sth return

答案 2 :(得分:1)

对于任何想要检查Any是否包含nil的方法的人:

如果调用po value会告诉您Any变量包含值nil,则以下行仍然不起作用:

if value == nil { ... } // Returns false and generates a warning

在检查之前,您必须先将其转换为可为空的值,例如当Any可能包含Date时:

if Optional<Date>.none == value as? Date { ... } // Returns true and no warning

注意:我没有测试它所以没有保证,但上面的行也可能在写成时通过:

if Optional<Any>.none == value as? Any { ... }