簡體   English   中英

如何通過忽略 Swift 中的關聯值來比較枚舉與關聯值?

[英]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 中,如果所有關聯的值都符合EquatableEquatable將被合成。 您需要做的就是添加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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM