Swift'deki ilişkili değerini yok sayarak enum'u ilişkili değerlerle nasıl karşılaştırabilirim?


90

İlişkili değerlerle Swift numaralandırmalarının eşitliği nasıl test edilir okuduktan sonra , aşağıdaki numaralandırmayı uyguladım:

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

Aşağıdaki kod çalışır:

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

Ancak, bu derlemez:

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

... ve aşağıdaki hata mesajını verir:

İkili operatör '==', 'CardRank' ve '(Int) -> CardRank' türündeki işlenenlere uygulanamaz

Bunun, tam bir tip beklemesinden ve tam bir türü CardRank.Numberbelirtmemesinden kaynaklandığını varsayıyorum , oysa CardRank.Number(2)yaptı. Ancak bu durumda herhangi bir sayı ile eşleşmesini istiyorum ; sadece belirli bir tane değil.

Açıkçası bir switch ifadesi kullanabilirim, ancak ==operatörü uygulamanın tüm amacı bu ayrıntılı çözümden kaçınmaktı:

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

İlişkili değerini göz ardı ederek bir numaralandırmayı ilişkili değerlerle karşılaştırmanın herhangi bir yolu var mı?

Not:== Yöntemdeki durumu olarak değiştirebileceğimin farkındayım case (.Number, .Number): return true, ancak doğru olarak dönecek olsa da, karşılaştırmam yine de herhangi bir sayıdan number == CardRank.Number(2)ziyade belirli bir sayı ( burada 2 bir kukla değerdir) ile karşılaştırılmış gibi görünecektir. ( ).number == CardRank.Number


1
Sen azaltabilir Jack, Queen, King, Acevakaları ==: Sadece için operatör uygulamasıcase (let x, let y) where x == y: return true
Alexander

Yanıtlar:


76

Düzenleme: Etan'ın belirttiği gibi, bunu (_)daha temiz kullanmak için joker karakter eşleşmesini atlayabilirsiniz .


Ne yazık ki switchSwift 1.2'deki yaklaşımınızdan daha kolay bir yol olduğuna inanmıyorum .

Ancak Swift 2'de yeni if-casekalıp eşleştirmesini kullanabilirsiniz:

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

Ayrıntıdan kaçınmak istiyorsanız, isNumbernumaranıza switch deyiminizi uygulayan bir hesaplanan özellik eklemeyi düşünebilirsiniz .


1
Bu kontrol akışı için harika ama sadece basit bir ifadeyi, örneğin istediğinizde bu tür berbat: assert(number == .Number). Sadece bunun Swift'in sonraki sürümlerinde iyileştirildiğini umabilirim. = /
Jeremy

3
Ayrıca while döngüsü koşulları vb. Şeyler için de berbattır. Swift 3'te daha temiz bir kod için (_) işaretini kaldırabilirsiniz.
Etan

Teşekkürler @Etan, bunu cevaba ekledim. Aslında Swift 2'de joker karakteri atlayabilirsiniz. Bu cevap, dil özelliği yayınlanmadan önce yazılmıştır, bu yüzden henüz bilmiyordum! :-D
Ronald Martin

Ayrıca: Bir numaralandırmanın ilişkili değerlere sahip tek bir durumu varsa, if-case modelinin ilişkili değerleri olmayan durumlar için bile kullanılması gerekir.
Etan

1
@PeterWarbo, bu kalıp eşleştirme sözdizimi ile olumsuzluk yapamazsınız. Şimdilik defaultbir switchbloktaki bir vakaya geri dönmeniz gerekecek .
Ronald Martin

29

Maalesef Swift 1.x'te başka bir yol yok, bu yüzden kullanman switchgereken Swift 2'nin kullanabileceğin versiyonu kadar zarif değil if case:

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

3
Ne yazık ki, bu sadece ififadelerde işe yarıyor , bir ifade olarak değil.
Raphael


3

İşte daha basit bir yaklaşım:

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

== operatörünü aşırı yüklemenize gerek yoktur ve kart türünü kontrol etmek kafa karıştırıcı sözdizimi gerektirmez:

let card = CardRank.Jack

if card == CardRank.Jack {
    print("You played a jack")
} else if !card.isFaceCard {
    print("You must play a face card!")
}

3
Her ne kadar kapsayıcı soruyu cevaplamasa da, IMO bu OP'lere benzer senaryolarda daha zarif bir çözümdür (numaralar bir yana) ve olumsuz oy verilmemelidir.
Nathan Hosselton

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.