web-dev-qa-db-fra.com

Comment comparer enum avec les valeurs associées en ignorant sa valeur associée dans Swift?

Après avoir lu Comment tester l'égalité de Swift enum avec les valeurs associées , j'ai implémenté l'énumération suivante:

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
    }
}

Le code suivant fonctionne:

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.")
}

Cependant, cela ne compile pas:

let number = CardRank.Number(5)
if number == CardRank.Number {
    print("You must play a face card!")
}

... et le message d'erreur suivant s'affiche:

L'opérateur binaire '==' ne peut pas être appliqué aux opérandes de type 'CardRank' et '(Int) -> CardRank'

Je suppose que c'est parce qu'il attend un type complet et que CardRank.Number Ne spécifie pas un type entier, alors que CardRank.Number(2) l'a fait. Cependant, dans ce cas, je veux qu’il corresponde à n’importe quel numéro ; pas seulement un spécifique.

Évidemment, je peux utiliser une instruction switch, mais le but de l'implémentation de l'opérateur == Était d'éviter cette solution prolixe:

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

Est-il possible de comparer une énumération avec des valeurs associées tout en ignorant sa valeur associée?

Remarque: Je réalise que je pourrais changer la casse de la méthode == En case (.Number, .Number): return true, mais retournerait vrai correctement, ma comparaison ressemblerait toujours comme si elle était comparée à un nombre spécifique (number == CardRank.Number(2); où 2 est une valeur factice) plutôt que toute nombre (number == CardRank.Number).

71
Senseful

Edit: Comme Etan le fait remarquer, vous pouvez omettre le (_) match générique pour utiliser ceci plus proprement.


Malheureusement, je ne pense pas qu'il existe un moyen plus facile que votre approche switch dans Swift 1.2.

Dans Swift 2, cependant, vous pouvez utiliser le nouveau if-case correspondance de modèle:

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

Si vous cherchez à éviter la verbosité, vous pouvez envisager d'ajouter une propriété calculée isNumber à votre enum qui implémente votre instruction switch.

63
Ronald Martin

Malheureusement, dans Swift 1.x, vous devez utiliser switch qui n’est pas aussi élégant que Swift 2 version où vous pouvez utiliser if case:

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

Dans Swift 4.2 Equatable sera synthétisé si toutes vos valeurs associées sont conformes à Equatable. Tout ce que vous avez à faire est d'ajouter 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

Voici une approche plus simple:

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)
    }
}

Il n'est pas nécessaire de surcharger l'opérateur == et la vérification du type de carte ne nécessite pas de syntaxe déroutante:

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