Search code examples
swiftenumscomparison

How to compare Swift enum with associated values by ignoring its associated value?


After reading How to test equality of Swift enums with associated values, I implemented the following enum:

enum CardRank {
    case Number(Int)
    case Jack
    case Queen
    case King
    case Ace
}

func ==(a: CardRank, b: CardRank) -> Bool {
    switch (a, b) {
    case (.Number(let a), .Number(let b))   where a == b: return true
    case (.Jack, .Jack): return true
    case (.Queen, .Queen): return true
    case (.King, .King): return true
    case (.Ace, .Ace): return true
    default: return false
    }
}

The following code works:

let card: CardRank = CardRank.Jack
if card == CardRank.Jack {
    print("You played a jack!")
} else if card == CardRank.Number(2) {
    print("A two cannot be played at this time.")
}

However, this doesn't compile:

let number = CardRank.Number(5)
if number == CardRank.Number {
    print("You must play a face card!")
}

... and it gives the following error message:

Binary operator '==' cannot be applied to operands of type 'CardRank' and '(Int) -> CardRank'

I'm assuming this is because it's expecting a full type and CardRank.Number does not specify an entire type, whereas CardRank.Number(2) did. However, in this case, I want it to match any number; not just a specific one.

Obviously I can use a switch statement, but the whole point of implementing the == operator was to avoid this verbose solution:

switch number {
case .Number:
    print("You must play a face card!")
default:
    break
}

Is there any way to compare an enum with associated values while ignoring its associated value?

Note: I realize that I could change the case in the == method to case (.Number, .Number): return true, but, although it would return true correctly, my comparison would still look like its being compared to a specific number (number == CardRank.Number(2); where 2 is a dummy value) rather than any number (number == CardRank.Number).


Solution

  • In Swift 2+ you can use the if-case pattern match:

    let number = CardRank.Number(5)
    if case .Number = number {
        // Is a number
    } else {
        // Something else
    }
    

    If you're looking to avoid verbosity, you might consider adding an isNumber computed property to your enum that implements your switch statement.