如何通过忽略Swift中的关联值来比较枚举与关联值?

时间:2015-07-21 20:20:32

标签: swift enums comparison

阅读How to test equality of Swift enums with associated values后,我实现了以下枚举:

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
    }
}

以下代码有效:

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.")
}

但是,这不会编译:

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

...并且它给出以下错误消息:

  

二元运算符'=='不能应用于'CardRank'和'(Int) - >类型的操作数。 CardRank'

我假设这是因为它期望完整类型而CardRank.Number没有指定整个类型,而CardRank.Number(2)则表示完整类型。但是,在这种情况下,我希望它匹配任何号码;不只是一个特定的。

显然我可以使用switch语句,但实现==运算符的重点是避免这个冗长的解决方案:

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

有没有办法比较枚举与关联值而忽略其关联值?

注意:我意识到我可以将==方法中的大小写更改为case (.Number, .Number): return true,但是,尽管它会正确返回,但我的比较仍然会像将其与特定数字(number == CardRank.Number(2);其中2是虚拟值)进行比较,而不是任何数字(number == CardRank.Number)。

6 个答案:

答案 0 :(得分:61)

编辑:正如Etan指出的那样,您可以省略(_)通配符匹配,以便更干净地使用它。

不幸的是,我不相信这比Swift 1.2中的switch方法更容易。

但是,在Swift 2中,您可以使用新的if-case模式匹配:

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

如果您希望避免冗长,可以考虑在实现switch语句的枚举中添加isNumber计算属性。

答案 1 :(得分:19)

不幸的是在Swift 1.x中没有其他方法,所以你必须使用switch,它不像Swift 2的版本那样优雅,你可以使用{{1 }}:

if case

答案 2 :(得分:14)

在Swift 4.2中,如果您所有关联的值都符合Equatable,则Equatable将被合成。您需要做的就是添加Equatable

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

https://developer.apple.com/documentation/swift/equatable?changes=_3

答案 3 :(得分:4)

这是一种更简单的方法:

enum CardRank {
    case Two
    case Three
    case Four
    case Five
    case Six
    case Seven
    case Eight
    case Nine
    case Ten
    case Jack
    case Queen
    case King
    case Ace

    var isFaceCard: Bool {
        return (self == Jack) || (self == Queen) || (self == King)
    }
}

不需要重载==运算符,检查卡类型不需要混淆语法:

let card = CardRank.Jack

if card == CardRank.Jack {
    print("You played a jack")
} else if !card.isFaceCard {
    print("You must play a face card!")
}

答案 4 :(得分:0)

您不需要func ==Equatable。只需使用enumeration case pattern

let rank = CardRank.Ace
if case .Ace = rank { print("Snoopy") }

答案 5 :(得分:0)

我不想符合 Equatable(它也没有帮助我)并且我想过滤除特定情况之外的其他情况,所以我不得不简单地写下 card != .Number写出以下内容。 (我针对这个问题调整了我的代码。)

enum CardRank {
    ...
    var isNumber: Bool {
       if case .Number = self { return true }
       return false
    }
}

所以我可以在复杂的条件下写不是数字

if something && !card.isNumber { ... }

我希望我可以只写 card != .Number,但编译器总是抱怨 没有更多上下文的表达式类型不明确。也许在即将推出的 swift 版本中!