Po przeczytaniu Jak testować równość wyliczeń Swift z powiązanymi wartościami zaimplementowałem następujące wyliczenie:
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
}
}
Poniższy kod działa:
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.")
}
Jednak to się nie kompiluje:
let number = CardRank.Number(5)
if number == CardRank.Number {
print("You must play a face card!")
}
... i daje następujący komunikat o błędzie:
Operator binarny „==” nie może być stosowany do operandów typu „CardRank” i „(Int) -> CardRank”
Zakładam, że CardRank.Number
dzieje się tak, ponieważ oczekuje pełnego typu i nie określa całego typu, podczas gdy CardRank.Number(2)
tak. Jednak w tym przypadku chcę, aby pasowała do dowolnej liczby; nie tylko konkretny.
Oczywiście mogę użyć instrukcji switch, ale celem wdrożenia ==
operatora było uniknięcie tego rozwlekłego rozwiązania:
switch number {
case .Number:
print("You must play a face card!")
default:
break
}
Czy istnieje sposób, aby porównać wyliczenie z powiązanymi wartościami, ignorując skojarzoną z nim wartość?
Uwaga: zdaję sobie sprawę, że mógłbym zmienić wielkość liter w ==
metodzie na case (.Number, .Number): return true
, ale chociaż zwracałoby to prawdę poprawnie, moje porównanie nadal wyglądałoby tak, jakby było porównywane z określoną liczbą ( number == CardRank.Number(2)
; gdzie 2 jest wartością fikcyjną), a nie z dowolną liczbą ( number == CardRank.Number
).
źródło
Jack
,Queen
,King
,Ace
przypadki, w==
realizacji operatora po prostu:case (let x, let y) where x == y: return true
Odpowiedzi:
Edycja: jak wskazuje Etan, możesz pominąć
(_)
dopasowanie z symbolem wieloznacznym, aby użyć go bardziej czysto.Niestety nie wierzę, że istnieje łatwiejszy sposób niż twoje
switch
podejście w Swift 1.2.W Swift 2 możesz jednak użyć nowego
if-case
dopasowania do wzorca:let number = CardRank.Number(5) if case .Number(_) = number { // Is a number } else { // Something else }
Jeśli chcesz uniknąć szczegółowości, możesz rozważyć dodanie
isNumber
obliczonej właściwości do wyliczenia, która implementuje instrukcję switch.źródło
assert(number == .Number)
. : . Mam tylko nadzieję, że poprawiono to w późniejszych wersjach Swifta. = /default
skrzynki wswitch
bloku.Niestety w Swift 1.x nie ma innego sposobu, więc musisz użyć,
switch
który nie jest tak elegancki jak wersja Swift 2, w której możesz użyćif case
:if case .Number = number { //ignore the value } if case .Number(let x) = number { //without ignoring }
źródło
if
stwierdzeń, a nie jako wyrażenia.W Swift 4.2
Equatable
zostaną zsyntetyzowane, jeśli wszystkie powiązane wartości będą zgodne zEquatable
. Wszystko, co musisz zrobić, to dodaćEquatable
.enum CardRank: Equatable { case Number(Int) case Jack case Queen case King case Ace }
https://developer.apple.com/documentation/swift/equatable?changes=_3
źródło
Oto prostsze podejście:
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) } }
Nie ma potrzeby przeciążania operatora ==, a sprawdzenie typu karty nie wymaga mylącej składni:
let card = CardRank.Jack if card == CardRank.Jack { print("You played a jack") } else if !card.isFaceCard { print("You must play a face card!") }
źródło
Nie potrzebujesz
func ==
lubEquatable
. Po prostu użyj wzorca wielkości liter wyliczenia .let rank = CardRank.Ace if case .Ace = rank { print("Snoopy") }
źródło