做者:Russ Bishop,原文連接,原文日期:2016-11-07
譯者:星夜暮晨;校對:walkingway;定稿:CMBgit
最近幾天,我在 Swift 用戶列表中參與了一個討論,主題是怎樣才能更好滴將包含字符串值的 JSON 數組轉換爲枚舉集 (Enumeration Set)。我半開玩笑地建議:這些字符串值應該被轉換到基於字符串的枚舉當中,而後這些值的 hashValues
將用於設置標誌位(flags)。github
固然,我很快(而且理所應當)被質疑道:『最終的解決方案是否應該取決於 hashValue
的實現細節』—— 很顯然不該該。可是隨着我思考的深刻,我猜測是否能夠經過哈希值來引導選項集 (Option Sets) 的建立,從而消除潛在的錯誤呢?swift
個人意思是假設有這樣一個枚舉:數組
private enum LaundryFlags: String { case lowWater, lowHeat, gentleCycle, tumbleDry }
咱們可使用枚舉值來生成選項集,由於咱們知道每一個 hashValue
都不會發生重疊,這使得編譯器能夠自行選擇實現的細節,而不用人工干涉:翻譯
public static let lowWater = LaundryOptions(rawValue: 1 << LaundryFlags.lowWater.hashValue)
這個方法讓咱們能夠從字符串中構建選項集,而無需關注具體的原始值 (Raw Value)。不管編譯器如何計算,最終的結果都是一致的:code
// 基於字符串的初始化操做 public init(strings: [String]) { let set: LaundryOptions = strings .flatMap({ LaundryFlags(rawValue: $0) }) // 轉換爲枚舉 .map({ 1 << $0.hashValue }) // 轉換爲 Int,即標誌值 .flatMap({ LaundryOptions(rawValue: $0) }) // 轉換爲選項集 .reduce([]) { $0.union($1) } // 聯結 _rawValue = set.rawValue }
不過這種作法也有限制。咱們沒法使用枚舉來表示以下所示的複合便利成員 (Compound Convenience Members):ip
public static let energyStar: LaundryOptions = [.lowWater, .lowHeat] public static let gentleStar: LaundryOptions = energyStar.union(gentleCycle)
此外,咱們能夠很容易地實現 CustomStringConvertible
協議,即使原始值枚舉沒法顯示它們的成員,而且也沒法使用哈希值來進行初始化。以下面這段代碼所示,生成一個延遲成員 (Lazy Member) 字典並不困難。咱們能夠將這個實現變爲樣板代碼 (Boiler Plate),而後將您的案例清單 (Case List) 複製/粘貼到這個數組當中:字符串
static var memberDict: Dictionary<Int, String> = [lowWater, lowHeat, gentleCycle, tumbleDry] .reduce([:]) { var dict = $0 dict[$1.hashValue] = "\($1)" return dict }
經過位運算,咱們即可以從選項集當中規約 (Reduce) 出這個字典:get
public var description: String { let members = LaundryFlags.memberDict.reduce([]) { return (rawValue & 1 << $1.key) != 0 ? $0 + [$1.value] : $0 } return members.joined(separator: ", ") }
因此讓咱們亮劍吧:考慮到這個方法是多麼地簡單可靠,那我還能繼續遵循『原始值枚舉以及它們的哈希值從不使用實現細節』的約定麼?編譯器
完整的 gist 代碼可在此查看。
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。