在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进行测试
答案 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 { ... }