混合構造器

做者:Russ Bishop,原文連接,原文日期:2016-11-09
譯者:Cyan;校對:小鐵匠Linus;定稿:CMBgit

今天的內容很是簡單,可是有些內容會讓人產生困擾,一般出如今 extensions 的上下文或者和 RawRepresentable 的枚舉值打交道的時候。github

沒法委託給可失敗的構造器

好比說你有個帶有可失敗構造器的類型。如今你想擴展這個類型讓他支持反序列化 JSON 數據。當 JSON 解析失敗的時候拋出一個友好且詳細的錯誤,而且你但願發生任何錯誤的時候都可以拋出來,無論是 JSON 解析仍是可失敗初始化器中的錯誤,若是咱們能拋出異常的話那是很好的。json

struct FizzFail {
    init?(string: String) { /* magic */ }
    init(json: JsonValue) throws {
        // 解析 json
        guard let string = json.string else { throw JsonError.invalidJson }
        // 錯誤:不可失敗的構造器沒法委託給可失敗的構造器
        if self.init(string: string) == nil {
            throw JsonError.missingValue
        }
    }
}

這裏有兩個問題。首先是咱們不能委託給可失敗構造器。當有人嘗試傳遞一個不合法的 JSON 數據時(這是不常見的對吧?),編譯器會幫助咱們將這個構造器轉換到一個可失敗的構造器,或者是插入一個不安全的解包類型,而後會終止掉。swift

其次,即使咱們能夠檢查可失敗構造器的結果,但沒有語法能夠這樣作。self 在可失敗構造器的上下文中只是一個可選值。安全

針對這個狀況有三種解決方案:.net

1.若是擁有對應的類型,能夠將實際初始化的代碼移到一個私有的可拋出異常的構造器裏面,而後公開的構造器都委託它來進行初始化。在可失敗構造器裏面使用 try? 來忽略錯誤。翻譯

struct Fizz {
    private init(value: String) throws { /* magic */ }
    init(json: JsonValue) throws {
        guard let string = json.string else {
            throw JsonError.invalidJson
        }
        try self.init(value: string)
    }
    init?(string: String) {
        try? self.init(value: string)
    }
}

2.若是不擁有類型而且它是一個值類型,你能夠對 self 從新賦值。這會致使額外的聲明和分配,可是代碼看起來會更清晰。code

extension FizzFail {
    init(json: JsonValue) throws {
        // 解析 json
        guard let string = json.string,
        let value = type(of: self).init(string: string) else {
            throw JsonError.invalidJson
        }
        self = value
    }
}

3.若是不擁有類型而且它是一個引用類型,那麼你必須使用一個靜態方法來解決,由於你沒有更好的選擇了。get

原始值

上面的技巧一樣適用於含有原始值(RawValue)的枚舉值。即便你擁有類型,你也不擁有自動生成的構造器,因此只能對 self 從新賦值:編譯器

enum Buzz: String {
    case wat = "wat"
    case other = "other"

    private enum ConstructionError: Error {
        case invalidConstruction
    }

    init(string: String) {
        if let value = type(of: self).init(rawValue: string) {
            self = value
        } else {
            self = .other
        }
    }
}

結束語

我在 30 分鐘裏寫完了這篇文章是爲了讓你知道,其實個人博客還在維護,最後謝謝你讀完。

Russ Bishop
這個博客僅表明我我的的觀點,並無獲得個人僱主的承認。

本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg

相關文章
相關標籤/搜索