Ich möchte die Gleichheit zweier Swift-Enum-Werte testen. Beispielsweise:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
Der Compiler kompiliert den Gleichheitsausdruck jedoch nicht:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
Muss ich meine eigene Überladung des Gleichheitsoperators definieren? Ich hatte gehofft, der Swift-Compiler würde das automatisch erledigen, ähnlich wie Scala und Ocaml.
Equatable
undHashable
Aufzählungen mit zugehörigen Werten.Antworten:
Swift 4.1+
Wie @jedwidz hilfreich hervorgehoben hat, unterstützt Swift ab Swift 4.1 (aufgrund von SE-0185 auch die Synthese von
Equatable
undHashable
für Aufzählungen mit zugehörigen Werten.Wenn Sie also Swift 4.1 oder höher verwenden, werden im Folgenden die erforderlichen Methoden automatisch so synthetisiert, dass sie
XCTAssert(t1 == t2)
funktionieren. Der Schlüssel ist, dasEquatable
Protokoll zu Ihrer Aufzählung hinzuzufügen .Vor Swift 4.1
Wie andere angemerkt haben, synthetisiert Swift die erforderlichen Gleichheitsoperatoren nicht automatisch. Lassen Sie mich jedoch eine sauberere Implementierung (IMHO) vorschlagen:
Es ist alles andere als ideal - es gibt viele Wiederholungen - aber zumindest müssen Sie keine verschachtelten Schalter mit darin enthaltenen if-Anweisungen ausführen.
quelle
default
mitcase (.Name, _): return false; case(.Number, _): return false
.case (.Name(let a), .Name(let b)) : return a == b
usw.false
? Es mag trivial sein, aber so etwas kann sich in bestimmten Systemen summieren.enum
und==
Funktion auf einem globalen Umfang umgesetzt werden müssen (außerhalb des Bereichs des View - Controller).Die Implementierung
Equatable
ist meiner Meinung nach ein Overkill. Stellen Sie sich vor, Sie haben eine komplizierte und große Aufzählung mit vielen Fällen und vielen verschiedenen Parametern. Diese Parameter müssen ebenfallsEquatable
implementiert sein. Und wer hat gesagt, dass Sie Enum-Fälle auf Alles-oder-Nichts-Basis vergleichen? Wie wäre es, wenn Sie den Wert testen und nur einen bestimmten Enum-Parameter stubben? Ich würde dringend einen einfachen Ansatz empfehlen, wie:... oder bei Parameterauswertung:
Eine ausführlichere Beschreibung finden Sie hier: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
quelle
if case
undguard case
sind einfach Sprachkonstrukte. Sie können sie in diesem Fall überall verwenden, wenn Sie die Gleichheit von Aufzählungen testen, nicht nur in Unit-Tests.Es scheint keinen vom Compiler generierten Gleichheitsoperator für Aufzählungen oder Strukturen zu geben.
Um einen Gleichheitsvergleich durchzuführen, würde man so etwas schreiben wie:
[1] Siehe "Äquivalenzoperatoren" unter https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43
quelle
Hier ist eine weitere Option. Es ist hauptsächlich dasselbe wie die anderen, außer dass die verschachtelten switch-Anweisungen mithilfe der
if case
Syntax vermieden werden . Ich denke, dies macht es etwas lesbarer (/ erträglicher) und hat den Vorteil, dass der Standardfall insgesamt vermieden wird.quelle
quelle
case (.Simple(let v0), .Simple(let v1))
Auch der Operator kann sichstatic
innerhalb der Aufzählung befinden. Siehe meine Antwort hier.Ich verwende diese einfache Problemumgehung im Unit-Test-Code:
Der Vergleich wird mithilfe der Zeichenfolgeninterpolation durchgeführt. Ich würde es nicht für Produktionscode empfehlen, aber es ist prägnant und erledigt die Aufgabe für Unit-Tests.
quelle
"\(lhs)" == "\(rhs)"
.String(describing:...)
oder das Äquivalent verwenden"\(...)"
. Dies funktioniert jedoch nicht, wenn sich die zugehörigen Werte unterscheiden :(Eine andere Möglichkeit wäre, die Zeichenfolgendarstellungen der Fälle zu vergleichen:
Beispielsweise:
quelle
Ein anderer Ansatz
if case
mit Kommas, der in Swift 3 funktioniert:So habe ich in meinem Projekt geschrieben. Aber ich kann mich nicht erinnern, woher ich die Idee hatte. (Ich habe gerade gegoogelt, aber keine solche Verwendung gesehen.) Jeder Kommentar wäre willkommen.
quelle
t1 und t2 sind keine Zahlen, sondern Instanzen von SimpleTokens mit zugeordneten Werten.
Sie können sagen
Das kannst du dann sagen
ohne Compilerfehler.
Verwenden Sie eine switch-Anweisung, um den Wert von t1 abzurufen:
quelle
Der 'Vorteil' im Vergleich zur akzeptierten Antwort besteht darin, dass die 'main'-switch-Anweisung keinen' Standard'-Fall enthält. Wenn Sie also Ihre Aufzählung mit anderen Fällen erweitern, zwingt Sie der Compiler, den Rest des Codes zu aktualisieren.
quelle
Um die Antwort von mbpro zu erweitern, habe ich diesen Ansatz verwendet, um die Gleichheit von schnellen Aufzählungen mit zugehörigen Werten mit einigen Randfällen zu überprüfen.
Natürlich können Sie eine switch-Anweisung ausführen, aber manchmal ist es hilfreich, nur in einer Zeile nach einem Wert zu suchen. Sie können es so machen:
Wenn Sie zwei Bedingungen in derselben if-Klausel vergleichen möchten, müssen Sie anstelle des
&&
Operators das Komma verwenden :quelle
Fügen Sie ab Swift 4.1 einfach ein
Equatable
Protokoll zu Ihrer Aufzählung hinzu und verwenden SieXCTAssert
oderXCTAssertEqual
:quelle
Sie können mit Schalter vergleichen
quelle