响应错误以及从错误中恢复的过程
抛出、捕获、传递、操作可回复错误
表示与抛出错误
Swift 中,错误用遵循 Error 空协议类型的值来表示用于错误处理
枚举构建一组错误状态
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
// 抛出错误
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
处理错误
4 种错误处理的方式
- 把函数抛出的错误传递给调用此函数的代码
- 用
do catch
语句处理错误 - 将错误作为可选类型处理 try?
- 断言此错误根本不会发生 try!
用 throwing 函数传递错误
一个标有关键字 throws 关键字的函数称为 throwing 函数
- throws 关键字需要写在返回值箭头(->)的前面
- 一个 throwing 函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域内
struct Item {
var price: Int
var count: Int
}
class VendingMachine {
var inventory = [
"Candy Bar": Item(price: 12, count: 7),
"Chips": Item(price: 10, count: 4),
"Pretzels": Item(price: 7, count: 11)
]
var coinsDeposited = 0
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else {
throws VendingMachineError.invalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.outOfStock
}
guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
}
coinsDeposited -= item.price
var newItem = item
newItem.count -= 1
inventory[name] = newItem
print("Dispensing \(name)")
}
}
函数抛出的错误传递给调用函数的代码
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels"
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName)
}
用 Do-Catch 处理错误
在 do 子句中的代码抛出错误,这个错误会与 catch 子句做匹配,从而决定哪条子句能处理它
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
print("Success! Yum.")
} catch VendingMachineError.invalidSelection {
print("Invalid Selection")
} catch VendingMachineError.outOfstock {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins")
} catch { // 如果一条 catch 子句没有匹配指定模式,那么这条子句可以匹配任何错误
print("Unexpected error: \(error).")
}
// 打印 Insufficient funds. Please insert an additional 2 coins
将错误转换成可选值
可以使用 try? 通过将错误转换成一个可选值来处理错误,抛出错误返回 nil
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
禁用错误传递
断言此 throwing 函数不会抛出错误 try!,如果抛出错误,程序奔溃
let photo = try! loadImage(atPath: "./Resource/John Appleseed.jpg")
指定清理操作
使用 defer 语句在 return 之前执行一系列代码
- 延迟执行的语句不能包含任何控制转移语句,例如 break、return 或是抛出一个错误
- 延迟执行操作会按照它们声明的顺序从后往前执行,也就是说第一个声明 defer 语句中的代码最后才执行
func processFile(filename: String) throws {
if exists(filename) {
let file = open(fileName)
defer {
close(file)
}
while let line = try file.readline() {
// 处理文件
}
// close(file) 会在这里被调用,即作用域的最后
}
}
网友评论