錯誤處理
表示并拋出錯誤
在Swift
中,錯誤用符合Error
協(xié)議的類型的值來表示。這個空協(xié)議表明該類型可以用于錯誤處理绵跷。
enum VendingError:Error {
case invalidSelection // 選擇無效
case insufficientFunds(coinsNeeded: Int) // 金額不足
case outOfStock // 缺貨
}
拋出一個錯誤可以讓你表明有意外情況發(fā)生叙量,導(dǎo)致正常的執(zhí)行流程無法繼續(xù)執(zhí)行。拋出錯誤使用throw
關(guān)鍵字甸陌。
throw VendingError.insufficientFunds(coinsNeeded: 2)
處理錯誤
某個錯誤被拋出時,附近的某部分代碼必須負(fù)責(zé)處理這個錯誤,例如糾正這個問題券腔、嘗試另外一種方式、或是向用戶報(bào)告錯誤拘泞。
throwing 函數(shù)傳遞錯誤
為了表示一個函數(shù)纷纫、方法或構(gòu)造器可以拋出錯誤,在函數(shù)聲明的參數(shù)列表之后加上throws
關(guān)鍵字陪腌。一個標(biāo)有throws
關(guān)鍵字的函數(shù)被稱作throwing
函數(shù)辱魁。如果這個函數(shù)指明了返回值類型,throws
關(guān)鍵詞需要寫在箭頭->
的前面诗鸭。
class VendingMachine {
var price = 5
var count = 10
func vend(coins: Int) throws {
// 投入的金額不足拋出錯誤 金額不足
guard coins >= price else {
throw VendingError.insufficientFunds(coinsNeeded: price-coins)
}
// 剩余量不足時拋出錯誤 缺貨
guard count - coins / price > 0 else {
throw VendingError.outOfStock
}
count = count - num;
}
}
Do-Catch 處理錯誤
可以使用一個do-catch
語句運(yùn)行一段閉包代碼來處理錯誤染簇。如果在do
子句中的代碼拋出了一個錯誤,這個錯誤會與catch
子句做匹配强岸,從而決定哪條子句能處理它锻弓。
let machine = VendingMachine()
do {
try machine.vend(coins: 3)
}
catch VendingError.outOfStock {
print("貨品不足")
}
catch VendingError.insufficientFunds(let coinsNeeded) {
print("還需要投入\(coinsNeeded)個硬幣")
}
// 打印 還需要投入3個硬幣
將錯誤轉(zhuǎn)換成可選值
可以使用try?
通過將錯誤轉(zhuǎn)換成一個可選值來處理錯誤。如果在評估try?
表達(dá)式時一個錯誤被拋出蝌箍,那么表達(dá)式的值就是nil
青灼。
enum SumError: Error {
case arrayIsEmpty
}
func getSum(numbers: Array<Int>) throws -> Int {
if numbers.count == 0 {
throw SumError.arrayIsEmpty
}
else {
var sum = 0
for num in numbers {
sum += num
}
return sum
}
}
let sum = try? getSum(numbers: [])
if let x = sum {
print(x)
} else {
print("數(shù)組為空")
}
禁用錯誤傳遞
有時你知道某個throwing
函數(shù)實(shí)際上在運(yùn)行時是不會拋出錯誤的,在這種情況下妓盲,你可以在表達(dá)式前面寫try!
來禁用錯誤傳遞杂拨,這會把調(diào)用包裝在一個不會有錯誤拋出的運(yùn)行時斷言中。如果真的拋出了錯誤悯衬,你會得到一個運(yùn)行時錯誤弹沽。
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
指定清理操作
可以使用defer
語句在即將離開當(dāng)前代碼塊時執(zhí)行一系列語句。該語句讓你能執(zhí)行一些必要的清理工作,不管是以何種方式離開當(dāng)前代碼塊的贷币,無論是由于拋出錯誤而離開击胜,還是由于諸如return
或者break
的語句。
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// 處理文件役纹。
}
// close(file) 會在這里被調(diào)用偶摔,即作用域的最后。
}
}
上面的代碼使用一條defer
語句來確保open(_:)
函數(shù)有一個相應(yīng)的對close(_:)
函數(shù)的調(diào)用促脉。
類型轉(zhuǎn)換
檢查類型
用類型檢查操作符is
來檢查一個實(shí)例是否屬于特定子類型辰斋。若實(shí)例屬于那個子類型,類型檢查操作符返回true
瘸味,否則返回false
宫仗。
class Animal {
}
class Dog: Animal {
var name: String
init(name: String) {
self.name = name
}
}
class Cat: Animal {
var name: String
init(name: String) {
self.name = name
}
}
let someDog = Dog(name: "旺財(cái)")
let someCat = Cat(name: "Kitty")
var animals: [Animal] = [someDog, someCat]
for animal in animals {
print(animal is Dog)
}
// true
// false
當(dāng)實(shí)例的類型不確定,可以用類型檢查來判斷類型旁仿。如果能夠確定類型那么這個判斷就是多余的:
let ret = someDog is Dog // 'is' test is always true
向下轉(zhuǎn)型
因?yàn)橄蛳罗D(zhuǎn)型可能會失敗藕夫,類型轉(zhuǎn)型操作符帶有兩種不同形式。條件形式as?
返回一個你試圖向下轉(zhuǎn)成的類型的可選值枯冈。強(qiáng)制形式as!
把試圖向下轉(zhuǎn)型和強(qiáng)制解包轉(zhuǎn)換結(jié)果結(jié)合為一個操作毅贮。
當(dāng)你不確定向下轉(zhuǎn)型可以成功時,用類型轉(zhuǎn)換的條件形式as?
尘奏。條件形式的類型轉(zhuǎn)換總是返回一個可選值滩褥,并且若下轉(zhuǎn)是不可能的,可選值將是nil
炫加。這使你能夠檢查向下轉(zhuǎn)型是否成功瑰煎。
只有你可以確定向下轉(zhuǎn)型一定會成功時,才使用強(qiáng)制形式as!
俗孝。當(dāng)你試圖向下轉(zhuǎn)型為一個不正確的類型時酒甸,強(qiáng)制形式的類型轉(zhuǎn)換會觸發(fā)一個運(yùn)行時錯誤。
for animal in animals {
if let cat = animal as? Cat {
print(cat.name)
}
}
// Kitty
Any 和 AnyObject 的類型轉(zhuǎn)換
Swift
為不確定類型提供了兩種特殊的類型別名:
-
Any
可以表示任何類型赋铝,包括函數(shù)類型烘挫。 -
AnyObject
可以表示任何類類型的實(shí)例。
var things: [Any] = [1, 2.5, "hello", (3, 5.0), someDog, someCat]
for thing in things {
switch thing {
case let someInt as Int:
print("\(someInt) is Int")
case let someDouble as Double:
print("\(someDouble) is Double")
case let someString as String:
print("\(someString) is String")
case let (x, y) as (Int, Double):
print("\(x) is Int, \(y) is Double")
case let someDog as Dog:
print("Dog is \(someDog.name)")
case let someCat as Cat:
print("Cat is \(someCat)")
default:
print("other")
}
}
// 1 is Int
// 2.5 is Double
// hello is String
// 3 is Int, 5.0 is Double
// Dog is 旺財(cái)
// Cat is Kitty