![](/img/trans.png)
[英]Compare Swift Enum types ignoring associated values - generic implementation
[英]How to compare enum with associated values by ignoring its associated value in Swift?
在閱讀了如何測試 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
}
}
以下代碼有效:
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
)。
編輯:正如 Etan 指出的那樣,您可以省略(_)
通配符匹配以更干凈地使用它。
不幸的是,我認為沒有比 Swift 1.2 中的switch
方法更簡單的方法。
但是,在 Swift 2 中,您可以使用新的if-case
模式匹配:
let number = CardRank.Number(5)
if case .Number(_) = number {
// Is a number
} else {
// Something else
}
如果您希望避免冗長,您可以考慮將isNumber
計算屬性添加到實現 switch 語句的枚舉中。
不幸的是,在 Swift 1.x 中沒有其他方法,因此您必須使用switch
,它不如 Swift 2 的版本那么優雅,您可以if case
使用:
if case .Number = number {
//ignore the value
}
if case .Number(let x) = number {
//without ignoring
}
在 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
這是一個更簡單的方法:
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!")
}
我不想符合Equatable
(它也沒有幫助我)並且我想過濾除特定情況以外的其他情況,所以不是簡單地寫card != .Number
我必須寫以下內容。 (我根據這個問題調整了我的代碼。)
enum CardRank {
...
var isNumber: Bool {
if case .Number = self { return true }
return false
}
}
所以我不能在復雜的條件下寫一個數字:
if something && !card.isNumber { ... }
我希望我可以只寫card != .Number
,但編譯器總是抱怨表達式類型不明確,沒有更多上下文。 也許在即將推出的 swift 版本中!
您不需要func ==
或Equatable
。 只需使用枚舉案例模式。
let rank = CardRank.Ace
if case .Ace = rank { print("Snoopy") }
如果兩個枚舉案例“匹配”,無論它們的關聯值如何,我通常會比較:
我有一個協議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
從 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.