web-dev-qa-db-ja.com

Swiftで関連付けられた値を無視して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
    }
}

次のコードが機能します。

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)はそうであると仮定しています。ただし、この場合、any番号と一致させます。特定のものだけではありません。

明らかにswitchステートメントを使用できますが、==演算子を実装する目的は、この冗長な解決策を避けることでした。

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

関連付けられた値を無視しながら、列挙値を関連付けられた値と比較する方法はありますか?

注:==メソッドの大文字と小文字をcase (.Number, .Number): return trueに変更できることに気づきましたが、それは正しくtrueを返しますが、私の比較それでも、any番号(number == CardRank.Number)ではなく、特定の番号(number == CardRank.Number(2); 2はダミー値)と比較されているように見えます。

71
Senseful

編集: 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ステートメントを実装する列挙型に追加することを検討してください。

63
Ronald Martin

残念ながらSwift 1.xには別の方法がないため、if caseを使用できるSwift 2のバージョンほどエレガントではないswitchを使用する必要があります。

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

In 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=_

15
nambatee

より簡単なアプローチを次に示します。

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
Mike Taverne