2015-01-09 19 views
14

Tôi đã gặp khó khăn khi tìm/hiểu tài liệu về cách so sánh enums trong Swift theo thứ tự định nghĩa của chúng. Cụ thể khi tôi tạo một đếm nhưThứ tự liệt kê Swift và so sánh

enum EnumType { 
    case First, Second, Third 
} 

Swift không cho phép tôi để so sánh trực tiếp enums theo lệnh, chẳng hạn như

let type1 = EnumType.First 
let type2 = EnumType.Second 
if type1 < type2 {println("good")} // error 

nó tạo ra lỗi biên dịch "không thể gọi '<' với danh sách đối số các loại {EnumType, EnumType}. vì vậy, giải pháp duy nhất tôi đã tìm thấy là viết khai thác của riêng tôi so sánh như quá tải, chẳng hạn như

enum EnumType : Int { 
    case First = 0, Second, Third 
} 

func <(a: EnumType, b: EnumType) -> Bool { 
    return a.rawValue < b.rawValue 
} 

let type1 = EnumType.First 
let type2 = EnumType.Second 
if type1 < type2 {println("good")} // Returns "good" 

Đây là tất cả tốt một thứ tốt cho các "enum nặng" có nhiều giá trị sử dụng và giá trị trong ứng dụng của tôi, nhưng quá tải tất cả các toán tử tôi muốn sử dụng dường như quá nặng nề đối với các enums "nhẹ" mà tôi có thể xác định khi bay hằng số cho một mô-đun nhỏ.

Có cách nào để thực hiện việc này mà không cần viết nhiều mã nạp chồng lên cho mỗi loại enum mà tôi xác định trong dự án của mình không? Thậm chí tốt hơn, có cái gì đó tôi đang thiếu để làm cho Swift tự động cung cấp các toán tử so sánh cho các enums đơn giản mà không có các kiểu liên quan, tức là. không được gõ hoặc gõ là Int? Swift biết cách so sánh Ints, vậy tại sao nó không thể so sánh enum Ints?

+1

Bạn có thể sử dụng thuộc tính 'hashValue', như được mô tả trong [câu trả lời này] (http://stackoverflow.com/a/27094973/148357). Hãy chắc chắn để đọc tuyên bố cuối cùng :) – Antonio

Trả lời

35

Miễn là bạn cho enum một loại cơ bản, nó sẽ tuân theo giao thức RawRepresentable.

Điều này có nghĩa bạn có thể viết một toán tử so sánh chung cho bất kỳ loại đó là biểu diễn thô, và có một loại nguyên liệu mà có thể so sánh, như vậy:

func <<T: RawRepresentable where T.RawValue: Comparable>(a: T, b: T) -> Bool { 
    return a.rawValue < b.rawValue 
} 

đó sẽ có nghĩa là enum của bạn sẽ tự động có một < điều hành:

enum E: Int { // this would work with Double and String also 
    // btw, no need to give a seed value of 0, 
    // that happens automatically for Ints 
    case A, B, C, D, E 
} 

E.A < E.C // returns true 

các bit duy nhất của soạn sẵn, bạn vẫn sẽ phải làm là thẻ enum của bạn như Comparable trong trường hợp bạn muốn sử dụng nó với các thuật toán chung mà đòi hỏi rằng:

extension E: Comparable { } 
// (no need for anything else - requirements are already fulfilled) 

let a: [E] = [.C, .E, .A] 
let b = sorted(a) 
// b will now be [.A, .C, .E] 

Làm cho nó phù hợp với Comparable cũng sẽ cung cấp cho nó <=, >>= nhà khai thác tự động (được cung cấp bởi thư viện tiêu chuẩn).

+7

Hoặc bạn chỉ có thể viết enum như enum E: Int, so sánh {..} Không có ý nghĩa trong việc có một dòng mở rộng ngẫu nhiên treo ra ở đó, IMO. –

+0

Phương pháp này có trả về đúng thứ tự cho chuỗi enum (ví dụ: "Z", chữ "A") không? Tôi đề nghị, toán tử so sánh sẽ trả về "Z"> "A", trường hợp của chúng ta là gì không chính xác. – brigadir

6

Đây cũng là một câu trả lời tương tự như bản OP đã đề xuất. Nó liên quan đến một chút mã boilerplate cho mỗi enum mà bạn muốn được so sánh, nhưng tôi thích điều này hơn là có một số chức năng ma thuật bên ngoài mà cung cấp so sánh với tất cả các enums. Điều đó có thể gây ra vấn đề nếu bạn thực hiện sao chép và dán nhanh từ một chương trình này sang chương trình khác, và sau đó enum không hoạt động và bạn không thể nhớ tại sao.

public enum LogLevel: Int, Comparable { 
    case verbose 
    case debug 
    case info 
    case warning 
    case error 
    case severe 

    // Implement Comparable 
    public static func < (a: LogLevel, b: LogLevel) -> Bool { 
     return a.rawValue < b.rawValue 
    } 
} 

EDIT:

Đây là để đáp lại một lời nhận xét của @JasonMoore.

So sánh không yêu cầu ==. Đó là yêu cầu của Equatable, và thư viện chuẩn Swift tự động cung cấp Equatable cho hầu hết các loại enums.

http://www.jessesquires.com/blog/swift-enumerations-and-equatable/

Đối với>, < = và> =, tài liệu Apple nói rằng họ được yêu cầu bởi tính năng tương đương, nhưng đó là một thực hiện mặc định được cung cấp (dựa trên sử dụng các toán tử == và <, tôi giả sử) .

https://developer.apple.com/documentation/swift/comparable

Dưới đây là một chút mã mà tôi chạy trong IBM Swift Sandbox - nó biên dịch và chạy tốt với các định nghĩa ở trên.

let a : LogLevel = LogLevel.verbose 
let b : LogLevel = LogLevel.verbose 
let c : LogLevel = LogLevel.warning 

print(a == b) // prints true 
print(a > c) // prints false 
print(a <= c) // prints true 
+1

Bạn cần thêm các phương thức '<=', '> =' và '>' để phù hợp với Comparable. Đó là một số tiền khó chịu của boilerplate. –

+1

@JasonMoore Vui lòng xem chỉnh sửa tôi đã thêm. – RenniePet

+2

Bạn nói đúng. 'Equatable' được tự động thêm vào enums (trừ khi bạn có một enum case với một biến). Và bạn có thể so sánh với Comparable bằng cách chỉ thực hiện '<'. Cảm ơn vì đã làm rõ điều đó. (Tôi có nên xóa bình luận của mình ở trên không?) –

Các vấn đề liên quan