String
并且String!
不相同。语言中恰好有足够的糖在它们之间进行转换。同样,语言中有糖可以在和之间进行转换String
(String?
但不能反过来)。
从基础开始。有String
。除非有一些强有力的理由,否则你应该String
在你的意思是一串字符时使用。其他一切都是“更多的东西”,除非你需要它,否则你不应该添加它。
有Optional<String>
。这只是一个有两种情况的枚举,一种有值,一种没有值:
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
// ...
}
有一个后缀运算符!
,如果可用Optional
则返回Wrapped
,如果不可用则崩溃。到目前为止,还没有魔法。这是你可以自己建造的东西。
周围有几件魔法Optional
。首先,类型被编译器Wrapped?
神奇地转换为(对于 any )。这只是语法糖。这两个符号是相同的。其次,存在与“操作符”的可选链接(它不是真正的操作符;它是语言的一部分,您无法自己构建它)。然后是可选的促销。如果需要,任何类型都可以自动隐式转换为。像语法这样的魔法很少有其他的东西,并且有一个同义词(我相信它们实际上是相同的)。但实际上只是一个泛型类型,实现为枚举。它'Optional<Wrapped>
Wrapped
?.
Wrapped
Wrapped?
Optional
if-let
nil
Optional.None
Optional
然后有ImplicitlyUnwrappedOptional<Wrapped>
。这也只是一个枚举(在 Swift 2.2 中;这将在 Swift 3 中改变)。
public enum ImplicitlyUnwrappedOptional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
// ...
}
这不一样,Optional
也不一样Wrapped
。这是一个完全不同的类型。但它也有一些与之相关的魔法。首先,类型Wrapped!
是ImplicitlyUnwrappedOptional<Wrapped>
. 再说一次,这只是糖。两者是相同的(在 Swift 2.2 中,而不是在 Swift 3 中)。接下来,如果IUO<Wrapped>
在预期的地方找到,如果没有值Wrapped
,它会自动转换为或崩溃。Wrapped
如果在Wrapped?
预期的地方找到它,它将自动转换为Wrapped?
. 这些很神奇,这就是为什么有时String
看起来String!
是同一类型的原因。这只是编译器通过添加一个不可见的转换步骤神奇地为您“使其工作”。这并不意味着它们真的是同一类型。
IUO 在桥接某些 Objective-C 模式时最有用,尤其是涉及 Storyboard,在这些情况之外应避免使用。即使在这些情况下,IUO 也只是为了方便。您可以使用常规 Optionals 做所有相同的事情,您只需要if-let
更频繁地检查它们。使用 Optionals 比使用 IUO 安全得多。很容易想到“我确定这个值总是在使用之前就设置好了”。就在本周,我追赶了一个撞车者,因为这件事是错误的。“它应该是”和“它必须是”之间是有区别的。但是,在 Storyboard 中使用 Optionals 完全安全可能会非常不方便,并且可能会掩盖一些错误(通过什么都不做而不是崩溃),所以这是 IUO 最常见的地方。
IUO 属性曾经对处理失败的init
方法很有价值。这在 Swift 2.2 中不再是一个问题,所以这种使用已经消失了。我遇到的最后一个“纯 Swift”使用是当您必须将self
存储为属性的内容传递给初始化程序时(此时您不能通过self
,因为您的所有属性都已初始化)。这是一个不幸的用例,非常混乱,我希望我们能找到解决办法。在这些情况之外,您应该避免隐式展开的选项。