引言
最近有幸参加公司的iOS招聘面试,发现很多3年左右工作经验的工程师对 swift 还停留在想要去了解的阶段,一些是由于公司项目的原因,一些是因为个人原因,但 swift 4.0 都已经出了,还在抱着观望的心态实在不像一个做技术的人应有的态度,所以最近想写一些跟 swift 相关的知识点,既作为自己对知识点的整理和保存,也希望能帮助到一些正在学习 swift 的小伙伴~~~
概念
空合运算符,当然这个运算符并不是 swift 首创,早在 C#,Perl,PHP7.0.0 等均有此运算符。
作用
这是一个非常有用而且常用的操作符,可以用来快速对 nil 进行条件判空,使代码看起来更加简洁。
- 使用之前
// 写法一:可选绑定(Optional Binding)
var username = ""
if let name = inputName {
username = name
} else {
username = "Guest"
}
// 写法二:三目运算符(ternary operator)
let username = inputName != nil ? inputName! : "Guest"
- 使用之后
let username = inputName ?? "Guest"
事实上 a ?? b 表示将对可选类型a进行为空判断,如果a包含一个值,就进行解封,否则就返回一个默认值b。
注意:表达式 a 必须是 Optional 类型。默认值 b 的类型必须要和 a 存储值的类型保持一致。
定义
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
- @autoclosure
@autoclosure作用就是把一句表达式自动地封装成一个闭包,@autoclosure并不支持带有输入参数的写法,只能使用类似 () -> T 的参数才能使用这个特性。所以写接受 @autoclosure 的方法时还需谨慎,在容易产生误解的时候,还是建议使用完整的闭包。
了解了 @autoclosure 之后 我们来猜一下 ?? 的实现
- 实现
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T {
switch optional {
case .Some(let value):
return value
case .None:
return defaultValue()
}
}
到这里我想除了 ?? 的实现之外,对 Optional 的实现应该也有所了解了
enum Optional<T> : Reflectable, NilLiteralConvertible {
case None
case Some(T)
init()
init(_ some: T)
...
}
当 Optional 没有值时,返回的 nil 其实就是 Optional.None,即没有值。除了 None 以外,还有一个 Some,当有值时就是被 Some(T) 包装的真正的值,所以拆包其实就是将Some里面的值取出来。
可能有些朋友会有疑问为什么这里要使用 @autoclosure,直接将 T 作为参数返回不行吗?这正是 @autoclosure 一个最值得称赞的地方。如果我们直接使用 T,那么意味着 ?? 操作符真正取值之前,我们就必须准备好一个默认值,这个默认值的准备和计算会降低性能。但如果 optional 不是 nil,就完全不需要这个默认值,会直接返回 optional 解包后的值。这种情况下默认值的准备就属于过度开销了。使用 @autoclosure 就是将默认值的计算推迟到 optional 确定为 nil 之后。