表示和抛出错误 (Representing and Throwing Errors)
使用符合 Error
协议的类型值来表示错误, 而枚举很适合:
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
抛出错误:
throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
处理错误 (Handling Errors)
传播错误 (Propagating Errors Using Throwing Functions)
使用 throw
标记一个可抛出错误的函数, 方法或初始化器:
func canThrowErrors() throws -> String
如果没有该标记, 则必须在函数内部处理该错误.
函数 vend
会传播错误:
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 {
throw 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)")
}
}
调用 vend
的函数:
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)
}
需要使用 try
关键字
结构体中传播错误:
struct PurchasedSnack {
let name: String
init(name: String, vendingMachine: VendingMachine) throws {
try vendingMachine.vend(itemNamed: name)
self.name = name
}
}
使用 Do-Catch (Handling Errors Using 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("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
print("Unexpected error: \(error).")
}
最后的 catch
用于处理意外情况
catch
中匹配多个错误:
func eat(item: String) throws {
do {
try vendingMachine.vend(itemNamed: item)
} catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
print("Invalid selection, out of stock, or not enough money.")
}
}
转换错误为可选值 (Converting Errors to Optional Values)
使用 try?
表达式, 如果发生错误则计算结果为 nil
:
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
等同于:
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
用于条件表达式:
func fetchData() -> Data? {
if let data = try? fetchDataFromDisk() { return data }
if let data = try? fetchDataFromServer() { return data }
return nil
}
禁止错误传播 (Disabling Error Propagation)
使用 try!
来表示不会发生错误:
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
如果发生错误将会直接报错, 错误也不会被传播出去
指定清除动作 (Specifying Cleanup Actions)
使用 defer
将必要的清除动作包含在其中, 无论代码块是否正常退出都会执行
❤️ 感谢你的访问,欢迎留言交流!❤️