Chcę przetestować równość dwóch wartości szybkiego wyliczenia. Na przykład:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
Jednak kompilator nie skompiluje wyrażenia równości:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
Czy mam zdefiniować własne przeciążenie operatora równości? Miałem nadzieję, że kompilator Swift poradzi sobie z tym automatycznie, podobnie jak robią to Scala i Ocaml.
Equatable
iHashable
wyliczanie z powiązanymi wartościami.Odpowiedzi:
Swift 4.1+
Jak pomocne @jedwidz , od Swift 4.1 (dzięki SE-0185 Swift obsługuje również syntezę
Equatable
iHashable
wyliczanie z powiązanymi wartościami.Jeśli więc korzystasz z wersji Swift 4.1 lub nowszej, poniższe elementy automatycznie zsyntetyzują niezbędne metody, które
XCTAssert(t1 == t2)
działają. Kluczem jest dodanieEquatable
protokołu do wyliczenia.Przed Swift 4.1
Jak zauważyli inni, Swift nie syntetyzuje automatycznie niezbędnych operatorów równości. Pozwólcie, że zaproponuję czystszą implementację (IMHO), jednak:
Jest daleki od ideału - jest wiele powtórzeń - ale przynajmniej nie musisz robić zagnieżdżonych przełączników z instrukcjami if w środku.
źródło
default
gocase (.Name, _): return false; case(.Number, _): return false
.case (.Name(let a), .Name(let b)) : return a == b
itd.false
? Może to być trywialne, ale tego rodzaju rzeczy mogą się sumować w niektórych systemach.enum
i==
funkcja musi być realizowana w ramach globalnej (poza zakresem kontrolera widoku).Wdrożenie
Equatable
to przesada IMHO. Wyobraź sobie, że masz skomplikowane i duże wyliczenie z wieloma przypadkami i wieloma różnymi parametrami. Te parametry również będą musiały zostaćEquatable
zaimplementowane. Ponadto, kto powiedział, że porównujesz przypadki wyliczeniowe na zasadzie „wszystko albo nic”? Co powiesz na to, jeśli testujesz wartość i wprowadziłeś tylko jeden konkretny parametr wyliczania? Zdecydowanie zaleciłbym proste podejście, takie jak:... lub w przypadku oceny parametrów:
Znajdź bardziej szczegółowy opis tutaj: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
źródło
if case
iguard case
są po prostu konstrukcjami językowymi, możesz ich użyć w dowolnym miejscu podczas testowania równości wyliczeń w tym przypadku, nie tylko w testach jednostkowych.Wydaje się, że nie ma generowanego przez kompilator operatora równości dla wyliczeń ani struktur.
Aby wdrożyć porównanie równości, należy napisać coś takiego:
[1] Patrz „Operatory równoważności” na stronie https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43
źródło
Oto kolejna opcja. Jest to głównie to samo, co inne, z tym wyjątkiem, że unika zagnieżdżonych instrukcji przełączania za pomocą
if case
składni. Myślę, że dzięki temu jest nieco bardziej czytelny (/ znośny) i ma tę zaletę, że całkowicie pomija domyślny przypadek.źródło
źródło
case (.Simple(let v0), .Simple(let v1))
Operator może również znajdować sięstatic
w wyliczeniu. Zobacz moją odpowiedź tutaj.Używam tego prostego obejścia w kodzie testu jednostkowego:
Używa interpolacji łańcuchów w celu wykonania porównania. Nie polecałbym go do kodu produkcyjnego, ale jest zwięzły i sprawdza się w testowaniu jednostkowym.
źródło
"\(lhs)" == "\(rhs)"
.String(describing:...)
lub ekwiwalentu"\(...)"
. Ale to nie działa, jeśli powiązane wartości różnią się :(Inną opcją byłoby porównanie reprezentacji ciągów przypadków:
Na przykład:
źródło
Inne podejście
if case
z użyciem przecinków, które działa w Swift 3:Tak napisałem w moim projekcie. Ale nie pamiętam, skąd pomysł. (Właśnie przejrzałem Google, ale nie widziałem takiego użycia). Wszelkie komentarze będą mile widziane.
źródło
t1 it2 nie są liczbami, są instancjami SimpleTokens z powiązanymi wartościami.
Możesz powiedzieć
Możesz wtedy powiedzieć
bez błędu kompilatora.
Aby pobrać wartość z t1, użyj instrukcji switch:
źródło
„zaletą” w porównaniu z zaakceptowaną odpowiedzią jest to, że w instrukcji przełącznika „głównego” nie ma przypadku „domyślnego”, więc jeśli rozszerzysz wyliczenie o inne przypadki, kompilator wymusi aktualizację reszty kodu.
źródło
Rozwijając odpowiedź mbpro, oto jak wykorzystałem to podejście do sprawdzenia równości szybkich wyliczeń z powiązanymi wartościami z niektórymi przypadkami krawędzi.
Oczywiście możesz wykonać instrukcję switch, ale czasem miło jest po prostu sprawdzić jedną wartość w jednym wierszu. Możesz to zrobić w następujący sposób:
Jeśli chcesz porównać 2 warunki w tej samej klauzuli if, musisz użyć przecinka zamiast
&&
operatora:źródło
W Swift 4.1 po prostu dodaj
Equatable
protokół do swojego wyliczenia i użyjXCTAssert
lubXCTAssertEqual
:źródło
Możesz porównać za pomocą przełącznika
źródło