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.