How to display OptionSet values in human-readable form?

后端 未结 5 1468
别跟我提以往
别跟我提以往 2021-02-13 21:17

Swift has the OptionSet type, which basically adds set operations to C-Style bit flags. Apple is using them pretty extensively in their frameworks. Examples include the options

5条回答
  •  梦毁少年i
    2021-02-13 21:47

    This article in NSHipster gives an alternative to OptionSet that offers all the features of an OptionSet, plus easy logging:

    https://nshipster.com/optionset/

    If you simply add a requirement that the Option type be CustomStringConvertible, you can log Sets of this type very cleanly. Below is the code from the NSHipster site - the only change being the addition of CustomStringConvertible conformance to the Option class

    protocol Option: RawRepresentable, Hashable, CaseIterable, CustomStringConvertible {}
    
    enum Topping: String, Option {
        case pepperoni, onions, bacon,
        extraCheese, greenPeppers, pineapple
    
        //I added this computed property to make the class conform to CustomStringConvertible
        var description: String {
            return ".\(self.rawValue)"
        }
    }
    
    extension Set where Element == Topping {
        static var meatLovers: Set {
            return [.pepperoni, .bacon]
        }
    
        static var hawaiian: Set {
            return [.pineapple, .bacon]
        }
    
        static var all: Set {
            return Set(Element.allCases)
        }
    }
    
    typealias Toppings = Set
    
    extension Set where Element: Option {
        var rawValue: Int {
            var rawValue = 0
            for (index, element) in Element.allCases.enumerated() {
                if self.contains(element) {
                    rawValue |= (1 << index)
                }
            }
            return rawValue
        }
    }
    

    Then using it:

    let toppings: Set = [.onions, .bacon]
    
    print("toppings = \(toppings), rawValue = \(toppings.rawValue)")
    

    That outputs

    toppings = [.onions, .bacon], rawValue = 6

    Just like you want it to.

    That works because a Set displays its members as a comma-delimited list inside square brackets, and uses the description property of each set member to display that member. The description property simply displays each item (the enum's name as a String) with a . prefix

    And since the rawValue of a Set is the same as an OptionSet with the same list of values, you can convert between them readily.

    I wish Swift would just make this a native language feature for OptionSets.

提交回复
热议问题