Swift Enumeration order and comparison

后端 未结 4 830
故里飘歌
故里飘歌 2021-02-18 15:59

I\'ve had trouble finding/understanding documentation on how to compare enums in Swift by their order of definition. Specifically when I create an enumeration such as



        
相关标签:
4条回答
  • 2021-02-18 16:05

    Comparing enums as the OP wanted will be possible from Swift 5.3 onwards.

    It works as below (from proposal):

    enum Brightness: Comparable {
        case low
        case medium
        case high
    }
    
    let expectedBrightness = Brightness.low
    let actualBrightness = Brightness.high
    
    if actualBrightness > expectedBrightness {
        // Do something
    }
    

    More info and examples here.

    0 讨论(0)
  • 2021-02-18 16:08

    So long as you give your enum an underlying type, it’ll conform to the protocol RawRepresentable.

    This means you can write a generic comparison operator for any type that is raw representable, and has a raw type that is comparable, like so:

    func <<T: RawRepresentable where T.RawValue: Comparable>(a: T, b: T) -> Bool {
        return a.rawValue < b.rawValue
    }
    

    which will mean your enum will automatically have a < operator:

    enum E: Int {  // this would work with Double and String also
        // btw, no need to give a seed value of 0,
        // that happens automatically for Ints
        case A, B, C, D, E
    }
    
    E.A < E.C  // returns true
    

    The only bit of boilerplate you’ll still have to do is tag your enum as Comparable in case you want to use it with generic algorithms that require that:

    extension E: Comparable { }
    // (no need for anything else - requirements are already fulfilled)
    
    let a: [E] = [.C, .E, .A]
    let b = sorted(a)
    // b will now be [.A, .C, .E]
    

    Making it conform to Comparable will also give it <=, >, and >= operators automatically (supplied by the standard library).

    0 讨论(0)
  • 2021-02-18 16:16

    This is to some extent the same answer as the OP proposed himself. It does involve a bit of boilerplate code for every enum that you want to be comparable, but I prefer this than having some external magic function that provides comparable to all enums. That can cause problems if you do a quick copy-and-paste from one program to another, and then the enum doesn't work and you can't remember why.

    public enum LogLevel: Int, Comparable {
        case verbose
        case debug
        case info
        case warning
        case error
        case severe
    
        // Implement Comparable
        public static func < (a: LogLevel, b: LogLevel) -> Bool {
            return a.rawValue < b.rawValue
        }
    }
    

    EDIT:

    This is in response to a comment by @JasonMoore.

    Comparable does not require ==. That is required by Equatable, and the Swift standard library automatically provides Equatable for most kinds of enums.

    http://www.jessesquires.com/blog/swift-enumerations-and-equatable/

    As for >, <= and >=, the Apple documentation says that they are required by Comparable, but that a default implementation is provided (based on use of == and <, I assume).

    https://developer.apple.com/documentation/swift/comparable

    Here's a bit of code that I ran in the IBM Swift Sandbox - it compiles and runs fine with the above definition.

    let a : LogLevel = LogLevel.verbose
    let b : LogLevel = LogLevel.verbose
    let c : LogLevel = LogLevel.warning
    
    print(a == b)  // prints true
    print(a > c)  // prints false
    print(a <= c)  // prints true
    
    0 讨论(0)
  • 2021-02-18 16:23

    In newer versions of Swift you can create a protocol to achieve this, without the need for generic globals. This also gives you the ability to choose which enums this affects.

    /// Allows a raw enum type to be compared by the underlying comparable RawValue
    public protocol RawComparable : Comparable where Self : RawRepresentable, RawValue: Comparable {
    }
    
    extension RawComparable {
        public static func < (lhs: Self, rhs: Self) -> Bool {
            return lhs.rawValue < rhs.rawValue
        }
    }
    

    To use this it's as simple as adding the RawComparable protocol to the enum type:

    enum EnumType : Int, RawComparable {
        case First = 0, Second, Third
    }
    
    0 讨论(0)
提交回复
热议问题