Swift 2.0 带来了两个新的能够简化程序和提高效率的控制流表达形式:guard 和 defer。前者可以让代码编写更流畅,后者能够让执行推迟。
guard
guard 是一个要求表达式的值为 true 从而继续执行的条件语句。如果表达式为 false,则会执行必须提供的 else 分支。
func sayHello(numberOfTimes: Int) {
guard numberOfTimes > 0 else {
return
}
}
使用 guard 来避免过多的缩进和错误
使用if可能在大段代码之后才写到异常情况,而使用guard每一个错误都在相应的检查之后立刻被抛出(尽早返回错误),使代码可读性更高。
不要在 guard 中双重否定
不要滥用这个新的流程控制机制——特别是在条件表达式已经表示否定的情况下。
举个例子,如果你想要在一个字符串为空是提早退出,不要这样写:
guard !string.isEmpty else {
return
}
defer
Swift 鼓励用尽早返回错误来代替嵌套 if 的处理方式。尽早返回让处理更清晰了,但是已经被初始化(可能也正在被使用)的资源必须在返回前被处理干净。
defer 关键字为此提供了安全又简单的处理方式:声明一个 block,当前代码执行的闭包退出时会执行该 block。
经常 defer
如果在同一个作用域内使用多个 defer
语句,它们会根据出现顺序反过来执行——像栈一样。这个反序是非常重要的细节,保证了被延迟的代码块创建时作用域内存在的东西,在代码块执行同样存在。
func test(){
defer {
print(3)
}
defer {
defer {
print(2)
}
print(1)
}
defer {
print(4)
}
}
打印结果:4
1
2
3
注:嵌套defer先执行外层,后执行内层。
正确 defer
如果在 defer 语句中引用了一个变量,执行时会用到变量最终的值。换句话说:defer 代码块不会捕获变量当前的值。
仔细 defer
另一件需要注意的事情,那就是 defer 代码块无法跳出它所在的作用域。因此如你尝试调用一个会 throw 的方法,抛出的错误就无法传递到其周围的上下文。
func burnAfterReading(file url: URL) throws {
defer { try FileManager.default.removeItem(at: url) }
// Errors not handled
let string = try String(contentsOf: url)
}
作为替代,你可以使用 try? 来无视掉错误,或者直接将语句移出 defer 代码块,将其放到函数的最后,正常的执行。