Swift12 - 错误处理、类型转换、嵌套类型

错误处理

错误用遵循 Error 协议的类型的值来表示

enum VendingMachineError: Error {
    case invalidSelection //选择无效
    case insufficientFunds(coinsNeeded: Int) //金额不足
    case outOfStock //缺货
}

在调用一个能抛出错误的函数、方法或者构造器之前,加上 try 关键字,或者 try? 或 try! 这种变体。
一个标有 throws 关键字的函数被称作 throwing 函数
func canThrowErrors() throws -> String

只有 throwing 函数可以传递错误。任何在某个非 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 {
            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",
]
// 调用加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).")
}

类型转换

使用 is 和 as 操作符实现。

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")
]// 数组 library 的类型被推断为 [MediaItem]

在幕后 library 里存储的媒体项依然是 Movie 和 Song 类型的。
但是,若你迭代它,依次取出的实例会是 MediaItem 类型的,而不是 Movie 和 Song 类型。
为了让它们作为原本的类型工作,你需要检查它们的类型或者向下转换它们到其它类型

检查类型:

用类型检查操作符(is)来检查一个实例是否属于特定子类型
计算数组 library 中 Movie 和 Song 类型的实例数量:

var moiveCount = 0
var songCount = 0

for item in library {
    if item is Movie {
        moiveCount += 1
    }else if item is Song {
        songCount += 1
    }
}
向下转型

某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试用类型转换操作符(as? 或 as!)向下转到它的子类型。
你不确定向下转型可以成功时,用类型转换的条件形式(as?)
只有你可以确定向下转型一定会成功时,才使用强制形式(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 的类型转换

Swift 为不确定类型提供了两种特殊的类型别名:

  • Any 可以表示任何类型,包括函数类型。
  • AnyObject 可以表示任何类类型的实例。

Any 类型可以表示所有类型的值,包括可选类型。Swift 会在你用 Any 类型来表示一个可选值的时候,给你一个警告。
如果你确实想使用 Any 类型来承载可选值,你可以使用 as 操作符显式转换为 Any,如下所示:

var things = [Any]()
let optionalNumber: Int? = 3
things.append(optionalNumber)        // 警告
things.append(optionalNumber as Any) // 没有警告

嵌套类型

要在一个类型中嵌套另一个类型,将嵌套类型的定义写在其外部类型的 {} 内,而且可以根据需要定义多级嵌套。

//例子
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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。