Swift Enumeration顺序和比较

Saf*_*ive 19 enums swift

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

enum EnumType {
    case First,  Second, Third
}
Run Code Online (Sandbox Code Playgroud)

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

let type1 = EnumType.First
let type2 = EnumType.Second
if type1 < type2 {println("good")} // error
Run Code Online (Sandbox Code Playgroud)

它生成编译错误"无法使用类型为{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"
Run Code Online (Sandbox Code Playgroud)

对于在我的应用程序中有很多用途和价值的"重量级"枚举,这一切都很好,但是重载我可能想要使用的所有操作符对于我可能定义的"轻量级"枚举似乎过于繁琐为一个小模块带来一些常量的顺序.

如果没有为我在项目中定义的每个枚举类型编写大量的样板重载代码,有没有办法做到这一点?更好的是,是否有一些我缺少的东西使Swift自动为没有相关类型的简单枚举提供比较运算符,即.是无类型的还是输入为Int?Swift知道如何比较Ints,为什么不能比较enum Ints呢?

Air*_*ity 43

只要你给你的枚举一个基础类型,它就符合协议RawRepresentable.

这意味着您可以为任何可原始表示的类型编写泛型比较运算符,并且具有可比较的原始类型,如下所示:

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

这意味着你的枚举将自动拥有一个<运算符:

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
Run Code Online (Sandbox Code Playgroud)

你仍然需要做的唯一的样板是标记你的枚举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]
Run Code Online (Sandbox Code Playgroud)

使其符合也Comparable将自动给它<=,>>=操作符(由标准库提供).

  • 或者你可以把enum写成enum E:Int,Comparable {..}没有任何意义,有一个随机的延伸线挂在那里,IMO. (11认同)

Ren*_*Pet 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
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这是对@JasonMoore的评论的回应.

可比较不需要==.这是Equatable所要求的,Swift标准库自动为大多数类型的枚举提供Equatable.

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

至于>,<=和> =,Apple文档说它们是Comparable所要求的,但提供了默认实现(基于使用==和<,我假设).

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
Run Code Online (Sandbox Code Playgroud)

  • 您需要添加方法`&lt;=`、`&gt;=` 和`&gt;` 以符合Comparable。这是一个烦人的样板文件。 (2认同)
  • 你是对的.`Equatable`会自动自动添加到枚举中(除非你有一个包含变量的枚举案例).并且只需实现`<`即可符合Comparable.谢谢你的澄清.(我应该删除上面的评论吗?) (2认同)

Dav*_*gle 7

在较新版本的 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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

enum EnumType : Int, RawComparable {
    case First = 0, Second, Third
}
Run Code Online (Sandbox Code Playgroud)


cre*_*emy 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
}
Run Code Online (Sandbox Code Playgroud)

更多信息和示例在这里