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

yzckvree  于 2022-10-31  发布在  Swift
关注(0)|答案(9)|浏览(181)

在阅读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,但是,尽管它会正确返回true,但我的比较看起来仍然像是在与一个特定的数字(number == CardRank.Number(2);其中2是虚拟值)而不是 * 任何 * 数字(number == CardRank.Number)。

w51jfk4q

w51jfk4q1#

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

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

不幸的是,我认为没有比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计算属性。

bqjvbblv

bqjvbblv2#

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

if case .Number = number {
    //ignore the value
}
if case .Number(let x) = number {
    //without ignoring
}
6qqygrtg

6qqygrtg3#

在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

ltskdhd1

ltskdhd14#

如果两个枚举案例“匹配”,不管它们的关联值是什么,我通常会比较:
我有一个协议Matchable

protocol Matchable {
  static func ~= (lhs: Self, rhs: Self) -> Bool
}

然后我让枚举符合它:

extension CardRank: Matchable {
  static func ~= (lhs: Self, rhs: Self) -> Bool {
    switch (lhs, rhs) {
      case
        (.number, .number),
        (.jack, .jack),
        (.queen, .queen),
        (.king, .king),
        (.ace, .ace):
        return true

      default:
        return false
    }
  }
}

let card1: CardRank = .number(1)
let card2: CardRank = .number(2)
let card3: CardRank = .jack

print(card1 ~= card2) // true
print(card1 ~= card3) // false
4uqofj5v

4uqofj5v5#

下面是一个更简单的方法:

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!")
}
anauzrmj

anauzrmj6#

我不想遵循Equatable(这对我也没有帮助),我想过滤除特定情况之外的其他情况,所以我不得不编写以下代码,而不是简单地编写card != .Number(我针对这个问题调整了我的代码)。

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

所以我可以写 * 不是一个数字 * 在一个复杂的条件:

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

我希望我可以只写card != .Number,但编译器总是抱怨**表达式的类型是模糊的,没有更多的上下文。**也许在即将到来的快速版本!

mrfwxfqh

mrfwxfqh7#

你不需要func ==Equatable,只需要使用一个枚举大小写模式。

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

anhgbhbe8#

extension CardRank {
    func isSameCaseAs(_ other: CardRank) -> Bool {
        switch (self, other) {
        case (.Number, .Number),
            (.Jack, .Jack),
            (.Queen, .Queen),
            (.King, .King),
            (.Ace, .Ace):
            return true
        default:
            return false
        }
    }
}

let number = CardRank.Number(1)
let otherNumber = CardRank.Number(2)
number.isSameCaseAs(otherNumber) // true

只需创建一个扩展并忽略关联的类型。

cnwbcb6i

cnwbcb6i9#

在Swift 5.3中,您可以使用Comparable Enums功能:

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

let cards: [CardRank] = [
    .Queen, .Number(8), .Ace, .Number(3), .King
]

print(cards.sorted())
// [.Number(3), .Number(8), .Queen, .King, .Ace]

相关问题