作者:Russ Bishop脸狸,原文鏈接钳枕,原文日期:2016-11-09
譯者:Cyan缴渊;校對:小鐵匠Linus;定稿:CMB
今天的內(nèi)容非常簡單鱼炒,但是有些內(nèi)容會讓人產(chǎn)生困擾衔沼,通常出現(xiàn)在 extensions 的上下文或者和 RawRepresentable
的枚舉值打交道的時候。
無法委托給可失敗的構(gòu)造器
比如說你有個帶有可失敗構(gòu)造器的類型∥羟疲現(xiàn)在你想擴展這個類型讓他支持反序列化 JSON 數(shù)據(jù)指蚁。當 JSON 解析失敗的時候拋出一個友好且詳細的錯誤,并且你希望發(fā)生任何錯誤的時候都能夠拋出來自晰,不管是 JSON 解析還是可失敗初始化器中的錯誤欣舵,如果我們能拋出異常的話那是很好的。
struct FizzFail {
init?(string: String) { /* magic */ }
init(json: JsonValue) throws {
// 解析 json
guard let string = json.string else { throw JsonError.invalidJson }
// 錯誤:不可失敗的構(gòu)造器無法委托給可失敗的構(gòu)造器
if self.init(string: string) == nil {
throw JsonError.missingValue
}
}
}
這里有兩個問題缀磕。首先是我們不能委托給可失敗構(gòu)造器缘圈。當有人嘗試傳遞一個不合法的 JSON 數(shù)據(jù)時(這是不常見的對吧?)袜蚕,編譯器會幫助我們將這個構(gòu)造器轉(zhuǎn)換到一個可失敗的構(gòu)造器糟把,或者是插入一個不安全的解包類型,然后會終止掉牲剃。
其次遣疯,即便我們可以檢查可失敗構(gòu)造器的結(jié)果,但沒有語法可以這樣做凿傅。self
在可失敗構(gòu)造器的上下文中只是一個可選值缠犀。
針對這個情況有三種解決方案:
1.如果擁有對應的類型,可以將實際初始化的代碼移到一個私有的可拋出異常的構(gòu)造器里面聪舒,然后公開的構(gòu)造器都委托它來進行初始化辨液。在可失敗構(gòu)造器里面使用 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
重新賦值滔迈。這會導致額外的聲明和分配止吁,但是代碼看起來會更清晰。
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.如果不擁有類型并且它是一個引用類型燎悍,那么你必須使用一個靜態(tài)方法來解決敬惦,因為你沒有更好的選擇了。
原始值
上面的技巧同樣適用于含有原始值(RawValue)的枚舉值谈山。即使你擁有類型俄删,你也不擁有自動生成的構(gòu)造器,所以只能對 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
}
}
}
結(jié)束語
我在 30 分鐘里寫完了這篇文章是為了讓你知道奏路,其實我的博客還在維護畴椰,最后謝謝你讀完。
Russ Bishop
這個博客僅代表我個人的觀點思劳,并沒有得到我的雇主的認可迅矛。
本文由 SwiftGG 翻譯組翻譯妨猩,已經(jīng)獲得作者翻譯授權(quán)潜叛,最新文章請訪問 http://swift.gg。