Swift Enumeration顺序和比较

时间:2015-01-09 21:17:48

标签: swift enums

我很难找到/理解如何按照定义顺序比较Swift中的枚举的文档。特别是当我创建一个枚举,如

enum EnumType {
    case First,  Second, Third
}

Swift不允许我按顺序直接比较枚举,例如

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

它生成编译错误“无法调用”&lt;'使用类型为{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,为什么不能比较enum Ints?

4 个答案:

答案 0 :(得分:39)

只要你给你的枚举一个基础类型,它就会符合协议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也会自动为<=>>=运算符提供(由标准库提供)。

答案 1 :(得分:10)

这在某种程度上与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/

对于&gt;,&lt; =和&gt; =,Apple文档说Comparable需要它们,但是提供了默认实现(基于使用==和&lt;,我假设)。< / p>

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

这是我在IBM Swift Sandbox中运行的一些代码 - 它使用上面的定义编译并运行良好。

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

答案 2 :(得分:5)

Swift 5.3 开始,可以将所需枚举与OP进行比较。

它的工作原理如下(根据提案):

enum Brightness: Comparable {
    case low
    case medium
    case high
}

let expectedBrightness = Brightness.low
let actualBrightness = Brightness.high

if actualBrightness > expectedBrightness {
    // Do something
}

更多信息和示例here

答案 3 :(得分:1)

在较新版本的Swift中,您可以创建协议来实现此目的,而无需通用全局变量。这也使您能够选择会影响哪个枚举。

/// Allows a raw enum type to be compared by the underlying comparable RawValue
public protocol RawComparable : Comparable where Self : RawRepresentable, RawValue: Comparable {
}

extension RawComparable {
    public static func < (lhs: Self, rhs: Self) -> Bool {
        return lhs.rawValue < rhs.rawValue
    }
}

要使用此功能,就像将RawComparable协议添加到枚举类型一样简单:

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