做者: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。