Je veux tester l'égalité de deux valeurs d'énumération Swift. Par exemple:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
Cependant, le compilateur ne compilera pas l'expression d'égalité:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
Dois-je définir ma propre surcharge de l'opérateur d'égalité? J'espérais que le compilateur Swift le gérerait automatiquement, un peu comme le font Scala et Ocaml.
Equatable
et lesHashable
énumérations avec les valeurs associées.Réponses:
Swift 4.1+
Comme @jedwidz l' a utilement souligné, à partir de Swift 4.1 (en raison de SE-0185 , Swift prend également en charge la synthèse
Equatable
et lesHashable
énumérations avec des valeurs associées.Donc, si vous êtes sur Swift 4.1 ou plus récent, ce qui suit synthétisera automatiquement les méthodes nécessaires pour que cela
XCTAssert(t1 == t2)
fonctionne. La clé est d'ajouter leEquatable
protocole à votre énumération.Avant Swift 4.1
Comme d'autres l'ont noté, Swift ne synthétise pas automatiquement les opérateurs d'égalité nécessaires. Permettez-moi de proposer une mise en œuvre plus propre (IMHO), cependant:
C'est loin d'être idéal - il y a beaucoup de répétitions - mais au moins vous n'avez pas besoin de faire des commutateurs imbriqués avec des instructions if à l'intérieur.
la source
default
parcase (.Name, _): return false; case(.Number, _): return false
.case (.Name(let a), .Name(let b)) : return a == b
etc.false
? Cela peut être trivial, mais ce genre de choses peut s'accumuler dans certains systèmes.enum
et la==
fonction doit être implémentée sur une portée globale (en dehors de la portée de votre contrôleur de vue).La mise en œuvre
Equatable
est une IMHO exagérée. Imaginez que vous ayez une énumération compliquée et volumineuse avec de nombreux cas et de nombreux paramètres différents. Ces paramètres devront tous avoir étéEquatable
implémentés également. De plus, qui a dit que vous compariez les cas d'énumération sur la base du tout ou rien? Que diriez-vous si vous testez la valeur et n'avez stubbed qu'un seul paramètre d'énumération particulier? Je suggérerais fortement une approche simple, comme:... ou en cas d'évaluation des paramètres:
Trouvez une description plus élaborée ici: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
la source
if case
etguard case
sont simplement des constructions de langage, vous pouvez les utiliser n'importe où lorsque vous testez l'égalité des énumérations dans ce cas, pas seulement dans les tests unitaires.la source
case (.Simple(let v0), .Simple(let v1))
aussi l'opérateur peut êtrestatic
à l'intérieur de l'énumération. Voir ma réponse ici.Il semble qu'aucun opérateur d'égalité généré par le compilateur pour les enums, ni pour les structs.
Pour implémenter la comparaison d'égalité, on écrirait quelque chose comme:
[1] Voir «Opérateurs d'équivalence» sur https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43
la source
Voici une autre option. C'est principalement le même que les autres sauf que cela évite les instructions de commutateur imbriquées en utilisant la
if case
syntaxe. Je pense que cela le rend légèrement plus lisible (/ supportable) et a l'avantage d'éviter complètement le cas par défaut.la source
J'utilise cette solution de contournement simple dans le code de test unitaire:
Il utilise une interpolation de chaîne pour effectuer la comparaison. Je ne le recommanderais pas pour le code de production, mais il est concis et fait le travail pour les tests unitaires.
la source
"\(lhs)" == "\(rhs)"
.String(describing:...)
ou l'équivalent"\(...)"
. Mais cela ne fonctionne pas si les valeurs associées diffèrent :(Une autre option serait de comparer les représentations sous forme de chaîne des observations:
Par exemple:
la source
Une autre approche utilisant
if case
des virgules, qui fonctionne dans Swift 3:C'est ainsi que j'ai écrit dans mon projet. Mais je ne me souviens pas d'où j'ai eu l'idée. (Je viens de googler mais je n'ai pas vu une telle utilisation.) Tout commentaire serait apprécié.
la source
t1 et t2 ne sont pas des nombres, ce sont des instances de SimpleTokens avec des valeurs associées.
Tu peux dire
Vous pouvez alors dire
sans erreur du compilateur.
Pour récupérer la valeur de t1, utilisez une instruction switch:
la source
«l'avantage» par rapport à la réponse acceptée est qu'il n'y a pas de cas «par défaut» dans l'instruction de commutateur «principal», donc si vous étendez votre énumération avec d'autres cas, le compilateur vous forcera à mettre à jour le reste du code.
la source
En développant la réponse de mbpro, voici comment j'ai utilisé cette approche pour vérifier l'égalité des énumérations rapides avec les valeurs associées avec certains cas extrêmes.
Bien sûr, vous pouvez faire une instruction switch, mais il est parfois agréable de ne vérifier qu'une seule valeur sur une ligne. Vous pouvez le faire comme ceci:
Si vous souhaitez comparer 2 conditions dans la même clause if, vous devez utiliser la virgule au lieu de l'
&&
opérateur:la source
Depuis Swift 4.1, ajoutez simplement un
Equatable
protocole à votre énumération et utilisezXCTAssert
ouXCTAssertEqual
:la source
Vous pouvez comparer en utilisant le commutateur
la source