錯誤處理
錯誤用遵循 Error 協(xié)議的類型的值來表示
enum VendingMachineError: Error {
case invalidSelection //選擇無效
case insufficientFunds(coinsNeeded: Int) //金額不足
case outOfStock //缺貨
}
在調(diào)用一個能拋出錯誤的函數(shù)、方法或者構造器之前瘫寝,加上 try 關鍵字蜒蕾,或者 try? 或 try! 這種變體。
一個標有 throws 關鍵字的函數(shù)被稱作 throwing 函數(shù)
func canThrowErrors() throws -> String
只有 throwing 函數(shù)可以傳遞錯誤焕阿。任何在某個非 throwing 函數(shù)內(nèi)部拋出的錯誤只能在函數(shù)內(nèi)部處理咪啡。
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
}
}
//do {
// try expression
// statements
//} catch pattern 1 {
// statements
//} catch pattern 2 where condition {
// statements
//} catch {
// statements
//}
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels",
]
// 調(diào)用加try關鍵字,并向上級拋出異常
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName)
}
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).")
}
類型轉(zhuǎn)換
使用 is 和 as 操作符實現(xiàn)暮屡。
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
let library = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Welles"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]// 數(shù)組 library 的類型被推斷為 [MediaItem]
在幕后 library 里存儲的媒體項依然是 Movie 和 Song 類型的撤摸。
但是,若你迭代它褒纲,依次取出的實例會是 MediaItem 類型的准夷,而不是 Movie 和 Song 類型。
為了讓它們作為原本的類型工作莺掠,你需要檢查它們的類型或者向下轉(zhuǎn)換它們到其它類型
檢查類型:
用類型檢查操作符(is)來檢查一個實例是否屬于特定子類型
計算數(shù)組 library 中 Movie 和 Song 類型的實例數(shù)量:
var moiveCount = 0
var songCount = 0
for item in library {
if item is Movie {
moiveCount += 1
}else if item is Song {
songCount += 1
}
}
向下轉(zhuǎn)型
某類型的一個常量或變量可能在幕后實際上屬于一個子類衫嵌。當確定是這種情況時,你可以嘗試用類型轉(zhuǎn)換操作符(as? 或 as!)向下轉(zhuǎn)到它的子類型彻秆。
你不確定向下轉(zhuǎn)型可以成功時楔绞,用類型轉(zhuǎn)換的條件形式(as?)
只有你可以確定向下轉(zhuǎn)型一定會成功時,才使用強制形式(as!)
for item in library {
if let movie = item as? Movie {
print("Movie: \(movie.name), dir. \(movie.director)")
}else if let song = item as? Song {
print("Song: \(song.name), by \(song.artist)")
}
}
Any 和 AnyObject 的類型轉(zhuǎn)換
Swift 為不確定類型提供了兩種特殊的類型別名:
- Any 可以表示任何類型唇兑,包括函數(shù)類型墓律。
- AnyObject 可以表示任何類類型的實例。
Any 類型可以表示所有類型的值幔亥,包括可選類型。Swift 會在你用 Any 類型來表示一個可選值的時候察纯,給你一個警告帕棉。
如果你確實想使用 Any 類型來承載可選值针肥,你可以使用 as 操作符顯式轉(zhuǎn)換為 Any,如下所示:
var things = [Any]()
let optionalNumber: Int? = 3
things.append(optionalNumber) // 警告
things.append(optionalNumber as Any) // 沒有警告
嵌套類型
要在一個類型中嵌套另一個類型香伴,將嵌套類型的定義寫在其外部類型的 {} 內(nèi)慰枕,而且可以根據(jù)需要定義多級嵌套。
//例子
struct BlackjackCard {
// 嵌套的Suit枚舉
enum Suit: Character {
case spades = "?", hearts = "?", diamonds = "?", clubs = "?"
}
//
enum Rank: Int {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values {
let first: Int, second: Int?
}
}
}
//引用嵌套類型
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue