[英]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:在阅读了如何测试 Swift 枚举与关联值的相等性之后,我实现了以下枚举:
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'
二元运算符'=='不能应用于'CardRank'和'(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.我假设这是因为它需要一个完整的类型,而
CardRank.Number
没有指定一个完整的类型,而CardRank.Number(2)
却指定了一个完整的类型。 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 语句,但实现
==
运算符的全部目的是避免这种冗长的解决方案:
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
).注意:我意识到我可以将
==
方法中的大小写更改为case (.Number, .Number): return true
,但是,尽管它会正确返回 true ,但我的比较仍然看起来像是在与特定数字进行比较( number == CardRank.Number(2)
; 其中 2 是一个虚拟值)而不是任何数字( number == CardRank.Number
)。
Edit: As Etan points out, you can omit the (_)
wildcard match to use this more cleanly.编辑:正如 Etan 指出的那样,您可以省略
(_)
通配符匹配以更干净地使用它。
Unfortunately, I don't believe that there's an easier way than your switch
approach in Swift 1.2.不幸的是,我认为没有比 Swift 1.2 中的
switch
方法更简单的方法。
In Swift 2, however, you can use the new if-case
pattern match:但是,在 Swift 2 中,您可以使用新的
if-case
模式匹配:
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.如果您希望避免冗长,您可以考虑将
isNumber
计算属性添加到实现 switch 语句的枚举中。
Unfortunately in Swift 1.x there isn't another way so you have to use switch
which isn't as elegant as Swift 2's version where you can use if case
:不幸的是,在 Swift 1.x 中没有其他方法,因此您必须使用
switch
,它不如 Swift 2 的版本那么优雅,您可以if case
使用:
if case .Number = number {
//ignore the value
}
if case .Number(let x) = number {
//without ignoring
}
In Swift 4.2 Equatable
will be synthesized if all your associated values conform to Equatable
.在 Swift 4.2 中,如果所有关联的值都符合
Equatable
则Equatable
将被合成。 All you need to do is add 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 https://developer.apple.com/documentation/swift/equatable?changes=_3
Here's a simpler approach:这是一个更简单的方法:
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)
}
}
There's no need to overload the == operator, and checking for card type does not require confusing syntax:无需重载 == 运算符,并且检查卡片类型不需要混淆语法:
let card = CardRank.Jack
if card == CardRank.Jack {
print("You played a jack")
} else if !card.isFaceCard {
print("You must play a face card!")
}
I didn't want to conform Equatable
(it didn't help me either) and I wanted to filter for other cases than a specific one, so instead of simply writing card != .Number
I had to write the following.我不想符合
Equatable
(它也没有帮助我)并且我想过滤除特定情况以外的其他情况,所以不是简单地写card != .Number
我必须写以下内容。 (I adjusted my code to this question.) (我根据这个问题调整了我的代码。)
enum CardRank {
...
var isNumber: Bool {
if case .Number = self { return true }
return false
}
}
So I can write not a number in a complex condition:所以我不能在复杂的条件下写一个数字:
if something && !card.isNumber { ... }
I wish I could just write card != .Number
, but the compiler was always complaining with Type of expression is ambiguous without more context.我希望我可以只写
card != .Number
,但编译器总是抱怨表达式类型不明确,没有更多上下文。 Maybe in an upcoming swift version!也许在即将推出的 swift 版本中!
You don't need func ==
or Equatable
.您不需要
func ==
或Equatable
。 Just use an enumeration case pattern .只需使用枚举案例模式。
let rank = CardRank.Ace
if case .Ace = rank { print("Snoopy") }
What I usually do to compare if two enum cases "match" no matter their associated value is:如果两个枚举案例“匹配”,无论它们的关联值如何,我通常会比较:
I have a protocol Matchable
:我有一个协议
Matchable
:
protocol Matchable {
static func ~= (lhs: Self, rhs: Self) -> Bool
}
Then I make enums conform to it:然后我让枚举符合它:
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
From Swift 5.3, you can use the Comparable Enums feature:从 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]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.