Swift 2.0之错误处理(下)

在上一篇文章中,我们学习了 Swift 2.0 错误处理的基本用法。

这篇文章将继续介绍 Swift 2.0 配合错误处理的两个新关键字,deferguard

defer

defer 关键字可以用来包裹一段代码,这个代码块将会在当前作用域结束的时候被调用。这通常被用来对当前的代码进行一些清理工作,比如关闭打开的文件等。

可以在同一个作用域中指定多个 defer 代码块,在当前作用域结束时,它们会以相反的顺序被调用,即先定义的后执行,后定义的先执行。

例如下面的代码:

openFile()
defer {
    // defer block 1
    closeFile()
}

startPortListener(42)
defer {
   // defer block 2
   stopPortListener(42)
}

这段代码在作用域结束的时候,第二个 defer 块将首先被调用,其次再调用第一个 defer 块。

guard

guard 关键字与 if 很相似, 只是作用与它相反。我们通常使用 if 用来选择自己想要的条件,而 guard 则是用来选择不想要的条件。

比如,有个程序员俱乐部规定在 github 上的 star 数少于 200 的不得入内。如果用 if 来进行判断,代码是这样的:

if star < 200 {
    return
}

如果使用 guard 的话,则应该是:

guard star >= 200 else {
    return
}

对于可选类型的绑定来说,guard 关键字的好处更加明显。下面的代码对比了这两种方法:

var star: Int?

if let star = star {
    // star 现在已经可以放心地使用了
}

guard let star = star else {
    return
}
// 从这里到本作用域结束,star都可以放心使用了

从段代码中可以看到,如果使用普通的 if-let 来对可选类型进行绑定,则意味着,我们必须在 if 语句的大括号里处理正常的情况,而在外面处理错误的情况。这与我们的直观感觉(特别是强迫症患者)不符。但是如果使用 guard 的话,我们可以提前判断出空的可选值,然后提前退出,在错误判断之后的代码中,star 都是解包过的,可以放心使用了。

Show me the code

这里继续使用上一篇文章中的 Demo,上一章的完整代码可以从我的github上下载到,文件名为 01-ErrorHandling.playground

starterShelf 函数之前,添加两个函数的定义:

func beginReceipt() {
    print("又要开始大采买了,真是买书如山倒啊")
}

func endReceipt() {
    print("购物结束,该去剁手去了")
}

接着,在调用purchaseBooks方法的前后,调用刚刚定义的两个函数:

do {
    beginReceipt()
    
    try shelf.purchaseBooks(2500)
    
    endReceipt()
} catch BookShelfError.NoEnoughSpace(let required) {
    print("书柜满啦,新买的书放不下咯。还差\(required)个空位,赶紧买个新书柜吧")
}

可以看到, 只有前一个函数的信息被打印出来了,那是因为在执行 purchaseBooks 方法的时候抛出了错误,程序的控制流程被转到了 catch 代码块里面,第二个函数没有获得执行。

这里,就可以使用 defer 来让 endReceiptdo 的作用域结束之前得到调用:

do {
    beginReceipt()
    defer {
        endReceipt()
    }
    
    try shelf.purchaseBooks(2500)
} catch BookShelfError.NoEnoughSpace(let required) {
    print("书柜满啦,新买的书放不下咯。还差\(required)个空位,赶紧买个新书柜吧")
}

现在,假设我们使用了一个字典来保存要在哪个书店购买几本书,将下面代码添加在 BookShelfError 的定义下面:

let shopList = ["新华书店": 250]

在调用 purchaseBooks 的时候,先从 shopList 里面取出要购买的数量:


do {
    // ...

    let buyCount = shopList["新华书店"]
    try shelf.purchaseBooks(buyCount)
} 

如果直接这样调用的话,编译器会报错,因为字典类型返回的是一个 Int? 的可选类型,所以不能直接使用。

这里,guard 关键字就可以派上用场了:

do {
    // ...

    guard let buyCount = shopList["新华书店"] else {
        fatalError()
    }
    
    try shelf.purchaseBooks(buyCount)
} 

这时,程序就就可以正常运行了。

作为练手,可以将 purchaseBookslendBooks 两个方法定义中的 if 改成使用 guard,这个很简单,就留给大家自己去尝试了。

本篇的完整代码可以到我的github上进行下载。

你可能感兴趣的:(Swift 2.0之错误处理(下))