我在Playground中尝试以下代码,我不太明白为什么编译器在从非可选函数返回bar
(nil
时不会出错;以及当nil
与nil
进行比较时为什么会这样做,并在声明foobar
永远不会是nil
时提供一条似乎不正确的错误消息。
编辑:
由于Optional
也是Any
,为什么不允许直接在nil
中返回foo2
?
func foo() -> Any {
let bar: String? = nil
return bar
}
let foobar = foo()
if foobar == nil {
}
func foo2() -> Any {
return nil
}
答案 0 :(得分:5)
编辑:由于Optional也是Any,为什么不允许直接在foo2中返回nil?
因为nil
没有自己的类型。它说什么都没有,但没有是什么?你必须选择那种类型:
func foo2() -> Any {
return nil as String?
}
即使这是合法的:
func foo2() -> Any {
return nil as Any?
}
但永远不要,永远不要这样做。 Any
不是常规工具。它是类型系统处理特殊问题(如print
)的最后一个逃生舱。当你将Any
的魔力与Optional
的魔力(特别是可选促销)混合在一起时,你会不断遇到混乱的错误并发现自己运行了错误的重载。
AnyObject
确实出现了一些问题,但仅仅是因为与ObjC的桥接,ObjC使用了无类型的值(尽管这种情况正在改善,AnyObject
变得越来越不常见)。但是在Swift代码中返回AnyObject
仍然很少有意义。
答案 1 :(得分:4)
让我们准确解释代码中发生的事情:
func foo() -> Any {
let bar: String? = nil
return bar
}
nil
是一个转换为String?
(或Optional<String>
)类型的文字,即Optional<String>.None
。
然后它被转换为Any
。任何东西都可以投射到Any
,包括选项。基本上你已经决定隐藏下划线类型。
然后foobar == nil
。请注意,==
是一项不会自动适用于所有类型的操作。与nil
的比较是在可选类型上定义的,例如Optional<T>
与另一个Optional<T>
。
在这种情况下,您有Any
和nil
字面值。 Any
本身不是可选的,因此您无法直接将其与nil
进行比较。
您可以将其投射到可选的Any
。
let optionalFoobar = any as Any?
但是,现在变量包含一个双重可选Optional<Any>.Some(Optional<String>.None)
,与nil
的比较不会起作用。
唯一可行的方法是:
if (foobar as Any?) as? String == nil {
print("is nil")
}
简而言之,请勿使用Any
,如果您使用的是非可选Any
,请不要将可选类型存储到其中,它会变得非常复杂且无法使用实践。
答案 2 :(得分:0)
Any
不是可选的,因此您无法与nil进行比较。如果要与nil进行比较,则返回类型必须是可选类型:Any?
例如:
func foo() -> Any? {
let bar: String? = nil
return bar
}
let foobar = foo()
if foobar == nil {
print("foobar is nil")
}