作者:Ole Begemann,原文鏈接痰腮,原文日期:2017-03-06
譯者:Cwift;校對:numbbbbb律罢;定稿:CMB
假設(shè)你有一個 Swift 的枚舉:
enum Expression {
case number(Double)
case string(String)
}
你希望它遵守 Equatable 協(xié)議膀值。由于該枚舉具有關(guān)聯(lián)值,必須手動添加误辑,所以需要實(shí)現(xiàn) == 函數(shù):
extension Expression: Equatable {
static func ==(lhs: Expression, rhs: Expression)
-> Bool {
switch (lhs, rhs) {
case let (.number(l), .number(r)): return l == r
case let (.string(l), .string(r)): return l == r
default: return false
}
}
}
這里處理了參數(shù)類型相同的兩種情況沧踏,比較類型不同時會執(zhí)行 default case 并返回 false。這種做法簡單直接巾钉,也沒錯:
Expression.number(1) == .number(1) // → true
Expression.number(1) == .string("a") // → false
Default case 會使得枚舉對窮盡的檢查無效
然而這段代碼有一個嚴(yán)重的缺陷:如果你在枚舉中添加另一個 case翘狱,編譯器不會警告你當(dāng)前枚舉的實(shí)現(xiàn)是不完整的。現(xiàn)在給枚舉添加第三種 case:
enum Expression {
case number(Double)
case string(String)
case bool(Bool)
}
只要能通過編譯器的檢查砰苍,那么這種行為就是合理的盒蟆。但執(zhí)行以下操作時代碼會返回錯誤的結(jié)果:
Expression.bool(true) == .bool(true) // → false!
switch 語句中的 default case 會使編譯器對枚舉的檢查無效踏烙。所以师骗,通常來說盡可能避免在 switch 語句中使用 default历等。
<center><font size=4>如果可能,盡量不要在 switch 語句中使用 default</font></center>
模式匹配大爆炸
沒有 default case 的缺點(diǎn)也很明顯:你需要寫更多的模式匹配代碼辟癌。下面是完全覆蓋三種 case 的寫法:
extension Expression: Equatable {
static func ==(lhs: Expression, rhs: Expression)
-> Bool {
switch (lhs, rhs) {
case let (.number(l), .number(r)): return l == r
case let (.string(l), .string(r)): return l == r
case let (.bool(l), .bool(r)): return l == r
case (.number, .string),
(.number, .bool),
(.string, .number),
(.string, .bool),
(.bool, .number),
(.bool, .string): return false
}
}
}
o(>﹏<)o寒屯!寫起來一點(diǎn)都不愉快,而且當(dāng)枚舉的 case 增加時會變得更糟黍少。switch 語句必須區(qū)分的狀態(tài)數(shù)會隨著枚舉中 case 的數(shù)量呈平方增長寡夹。
從平方增長到線性增長
_ 占位符可以簡化你的 switch 語句。雖然不能使用 default 語句厂置,但是我們可以把上一段代碼最后的六行簡化成三行:
extension Expression: Equatable {
static func ==(lhs: Expression, rhs: Expression)
-> Bool {
switch (lhs, rhs) {
case let (.number(l), .number(r)): return l == r
case let (.string(l), .string(r)): return l == r
case let (.bool(l), .bool(r)): return l == r
case (.number, _),
(.string, _),
(.bool, _): return false
}
}
}
這個方案更好菩掏,枚舉中每增加一個 case,switch 語句只會增加兩行昵济,不再是平方級的增加智绸。而且你保留了編譯器窮盡檢查的優(yōu)勢:添加一個新 case,編譯器會報(bào) == 的錯誤访忿。
Sourcery
如果你覺得重復(fù)代碼還是太多瞧栗,可以看看 Krzysztof Zab?ocki 開發(fā)的代碼生成工具 Sourcery。在類似的應(yīng)用場景中海铆,它可以自動為枚舉以及其他類型生成 Equatable 協(xié)議所需的代碼(并且不斷更新生成代碼)迹恐。
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán)卧斟,最新文章請?jiān)L問 http://swift.gg殴边。