view raw
Senseful Senseful - 7 months ago 55
Swift Question

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

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
does not specify an entire type, whereas
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!")

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


Edit: As Etan points out, you can omit the (_) wildcard match to use this more cleanly.

Unfortunately, I don't believe that there's an easier way than your switch approach in Swift 1.2.

In Swift 2, however, you can use the new 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.