2015-01-09 112 views
14

我一直很難找到/理解如何比較Swift中的枚舉的定義順序的文檔。特別是當我創建一個枚舉如快速枚舉的順序和比較

enum EnumType { 
    case First, Second, Third 
} 

斯威夫特不允許我按訂單直接比較枚舉,如

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

它生成的編譯錯誤「不能援引‘<’與參數列表{EnumType,EnumType}的類型。所以,我已經找到了唯一的解決辦法就是寫我自己的比較操作過載,如

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" 

這是一個好一個對於在我的應用程序中具有很多用途和價值的「重量級」枚舉有好處,但是對於我可能想要使用的所有操作符來說,重載過度似乎對於我可能定義的「輕量級」枚舉過於繁瑣,以便爲某些命令一個小模塊的常量。

有沒有辦法做到這一點,而無需爲我在項目中定義的每個枚舉類型編寫大量的樣板重載代碼?更妙的是,有什麼我錯過讓Swift自動提供比較運算符的簡單枚舉沒有關聯類型,即。是無類型的還是輸入爲Int? Swift知道如何比較Ints,爲什麼它不能比較枚舉Ints?

+1

您可以使用'hashValue'屬性,如[本答案](http://stackoverflow.com/a/27094973/148357)中所述。請務必閱讀最後一條語句:) – Antonio 2015-01-09 21:28:41

回答

35

只要你給你的枚舉一個基礎類型,它將符合協議RawRepresentable

這意味着你可以寫任何類型的原料可表示一個通用的比較操作,並具有原始類型,它是相當的,就像這樣:

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

這將意味着你的枚舉將自動獲得一個<運營商:

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 

的樣板,你仍然必須做的唯一的一點是你的標籤如枚舉在Comparable如果你想與需要泛型算法使用的是:

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] 

使之符合Comparable也會給它<=>,和>=運營商自動地(通過標準庫提供)。

+7

或者您可以將enum編寫爲enum E:Int,Comparable {..}沒有任何意義可以隨機添加延長線,IMO。 – 2016-05-03 17:35:20

+0

此方法是否返回字符串枚舉的正確順序(例如「Z」,情況「A」)?我建議,比較運算符會返回「Z」>「A」,這對我們的情況是不正確的。 – brigadir 2016-07-22 13:36:45

6

這在某種程度上與OP提出的自己的答案相同。它確實包含了你想要比較的每個枚舉的一些樣板代碼,但是我更喜歡這個,而不是具有一些與所有枚舉相媲美的外部魔術函數。如果你從一個程序快速複製並粘貼到另一個程序,那麼這可能會導致問題,然後枚舉不起作用,你不記得原因。

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

編輯:

這是響應由@JasonMoore評論。

可比較不需要==。這是Equatable所要求的,Swift標準庫爲大多數枚舉自動提供Equatable。

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

至於>,< =和> =,蘋果的文件說,他們被要求相媲美,但是默認的實現提供了(根據使用==和<的,我假設) 。

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

下面是一些代碼,我在IBM斯威夫特沙箱跑了 - 它編譯和運行良好上述定義。

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

您需要添加方法'<=', '> ='和'>'以符合Comparable。這是一個令人討厭的樣板。 – 2017-05-10 19:05:21

+1

@JasonMoore請參閱我已添加的修改。 – RenniePet 2017-06-20 23:55:41

+2

你是對的。 「Equatable」會自動添加到枚舉中(除非您有一個帶變量的枚舉類型)。你可以通過執行'<'來符合Comparable。謝謝澄清。 (我應該刪除我的評論嗎?) – 2017-06-21 13:21:22