Làm thế nào để so sánh enum với các giá trị liên quan bằng cách bỏ qua giá trị liên quan của nó trong Swift?


87

Sau khi đọc Cách kiểm tra tính bình đẳng của enum Swift với các giá trị được liên kết , tôi đã triển khai enum sau:

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

Đoạn mã sau hoạt động:

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

Tuy nhiên, điều này không biên dịch:

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

... và nó đưa ra thông báo lỗi sau:

Toán tử nhị phân '==' không thể được áp dụng cho các toán hạng thuộc loại 'CardRank' và '(Int) -> CardRank'

Tôi giả định điều này là do nó mong đợi một loại đầy đủ và CardRank.Numberkhông chỉ định một loại toàn bộ, trong khi đó CardRank.Number(2). Tuy nhiên, trong trường hợp này, tôi muốn nó khớp với bất kỳ số nào ; không chỉ là một cái cụ thể.

Rõ ràng là tôi có thể sử dụng một câu lệnh switch, nhưng toàn bộ điểm của việc triển ==khai toán tử là để tránh giải pháp dài dòng này:

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

Có cách nào để so sánh một enum với các giá trị được liên kết trong khi bỏ qua giá trị được liên kết của nó không?

Lưu ý: Tôi nhận ra rằng tôi có thể thay đổi trường hợp trong ==phương thức thành case (.Number, .Number): return true, nhưng, mặc dù nó sẽ trả về true một cách chính xác, so sánh của tôi vẫn trông giống như so với một số cụ thể ( number == CardRank.Number(2); trong đó 2 là một giá trị giả) hơn là bất kỳ số nào ( number == CardRank.Number).


1
Bạn có thể giảm Jack, Queen, King, Acetrường hợp trong ==thực hiện hành để chỉ:case (let x, let y) where x == y: return true
Alexander - Khôi phục Monica

Câu trả lời:


72

Chỉnh sửa: Như Etan đã chỉ ra, bạn có thể bỏ qua (_)đối sánh ký tự đại diện để sử dụng điều này rõ ràng hơn.


Thật không may, tôi không tin rằng có một cách dễ dàng hơn cách switchtiếp cận của bạn trong Swift 1.2.

Tuy nhiên, trong Swift 2, bạn có thể sử dụng if-casekhớp mẫu mới :

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

Nếu bạn đang muốn tránh dài dòng, bạn có thể cân nhắc việc thêm một thuộc isNumbertính tính toán vào enum để triển khai câu lệnh switch của bạn.


1
Đây là tuyệt vời cho dòng điều khiển, nhưng nó kinda sucks khi bạn chỉ muốn một biểu thức đơn giản, ví dụ như: assert(number == .Number). Tôi chỉ có thể hy vọng điều này sẽ được cải thiện trong các phiên bản Swift sau này. = /
Jeremy

3
Ngoài ra, những thứ như điều kiện vòng lặp while, v.v. Trong Swift 3, bạn có thể loại bỏ dấu (_) để có mã sạch hơn.
Etan

Cảm ơn @Etan, tôi đã thêm điều đó vào câu trả lời. Bạn cũng có thể bỏ qua ký tự đại diện trong Swift 2. Câu trả lời này được viết trước khi tính năng ngôn ngữ được phát hành, vì vậy tôi chưa biết điều đó! :-D
Ronald Martin

Ngoài ra: Nếu một enum có một trường hợp duy nhất với các giá trị được liên kết, thì mẫu if-case cần được sử dụng ngay cả cho những trường hợp không có giá trị liên kết.
Etan

1
@PeterWarbo, bạn không thể phủ định bằng cú pháp đối sánh mẫu này. Bây giờ bạn sẽ phải quay lại một defaulttrường hợp trong một switchkhối.
Ronald Martin

28

Thật không may trong Swift 1.x, không có cách nào khác để bạn phải sử dụng cách switchnày không trang nhã như phiên bản Swift 2, nơi bạn có thể sử dụng if case:

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

3
Đáng buồn thay, điều này chỉ hoạt động trong các ifcâu lệnh, không phải là một biểu thức.
Raphael


3

Đây là một cách tiếp cận đơn giản hơn:

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

Không cần quá tải toán tử == và việc kiểm tra loại thẻ không yêu cầu cú pháp khó hiểu:

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
Mặc dù nó không trả lời câu hỏi bao quát, IMO đây là một giải pháp thanh lịch hơn (sang một bên Các số được liệt kê) trong các tình huống tương tự như OP và không nên bị bỏ phiếu từ chối.
Nathan Hosselton

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.