IT技术博客大学习 共学习 共进步

Swift的多重 Optional

Swifter 2016-01-27 22:33:27 浏览 1,882 次

   Optional 可以说是 Swift 的一大特色,它完全解决了 “有” 和 “无” 这两个困扰了 Objective-C 许久的哲学概念,也使得代码安全性得到了很大的增加。但是一个陷阱 -- 或者说一个很容易让人迷惑的概念 -- 也随之而来,那就是多重的 Optional。

   在深入讨论之前,可以让我们先看看 Optional 是什么。很多读者应该已经知道,我们使用的类型后加上 ? 的语法只不过是 Optional 类型的语法糖,而实际上这个类型是一个 enum:

enum Optional<T> : _Reflectable, NilLiteralConvertible {  
    case None
    case Some(T)

    //...
}

   在这个定义中,对 T 没有任何限制,也就是说,我们是可以在 Optional 中装入任意东西的,甚至也包括 Optional 对象自身。打个形象的比方,如果我们把 Optional 比作一个盒子,实际具体的 String 或者 Int 这样的值比作糖果的话,当我们打开一个盒子 (unwrap) 时,可能的结果会有三个 -- 空气,糖果,或者另一个盒子。

   空气和糖果都很好理解,也十分直接。但是对于盒子中的盒子,有时候使用时就相当容易出错。特别是在和各种字面量转换混用的时候需要特别注意。

   对于下面这种形式的写法:

var string: String? = "string"  
var anotherString: String?? = string  

   我们可以很明白地知道 anotherString 是 Optinal<Optional<String>>。但是除开将一个 Optional 值赋给多重 Optional 以外,我们也可以将直接的字面量值赋给它:

var literalOptional: String?? = "string"  

   这种情况还好,根据类型推断我们只能将 Optional<String> 放入到 literalOptional 中,所以可以猜测它与上面提到的 anotherString 是等效的。但是如果我们是将 nil 赋值给它的话,情况就有所不同了。考虑下面的代码:

var aNil: String? = nil

var anotherNil: String?? = aNil  
var literalNil: String?? = nil  

   anotherNil 和 literalNil 是不是等效的呢?答案是否定的。anotherNil 是盒子中包了一个盒子,打开内层盒子的时候我们会发现空气;但是 literalNil 是盒子中直接是空气。使用中一个最显著的区别在于:

if let a = anotherNil {  
    print("anotherNil")
}

if let b = literalNil {  
    print("literalNil")
}

   这样的代码只能输出 anotherNil。

   另一个值得注意的地方时在Playground 中运行时,或者在用 lldb 进行调试时,直接使用 po 指令打印 Optional 值的话,为了看起来方便,lldb 会将要打印的 Optional 进行展开。如果我们直接打印上面的 anotherNil 和 literalNil,得到的结果都是 nil:

(lldb) po anotherNil
nil

(lldb) po literalNil
nil  

   如果我们遇到了多重 Optional 的麻烦的时候,这显然对我们是没有太大帮助的。我们可以使用 fr v -R 命令来打印出变量的未加工过时的信息,就像这样:

(lldb) fr v -R anotherNil
(Swift.Optional<Swift.Optional<Swift.String>>)
    anotherNil = Some {
    ... 中略
}
(lldb) fr v -R literalNil
(Swift.Optional<Swift.Optional<Swift.String>>)
    literalNil = None {
    ... 中略
}

   这样我们就能清晰地分辨出两者的区别了。

建议继续学习

  1. OpenStack Swift源码导读之——业务整体架构和Proxy进程 (阅读 4,423)
  2. Swift 性能探索和优化分析 (阅读 3,641)
  3. 你应该更新的Java知识之Optional (阅读 2,982)
  4. Openstack Swift简介 (阅读 2,743)
  5. Swift ABI 稳定对我们到底意味着什么 (阅读 2,122)
  6. 自己动手使用 Swift 打造全功能 JSON 解析、生成库 (阅读 2,063)
  7. Swift错误和异常处理 (阅读 1,785)
  8. Swift隐式解包 Optional (阅读 1,504)