【问题标题】:Swift Enumeration order and comparisonSwift枚举顺序和比较
【发布时间】:2015-01-09 21:17:48
【问题描述】:

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

enum EnumType {
    case First,  Second, Third
}

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

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,为什么不能比较 enum Ints?

【问题讨论】:

  • 您可以使用hashValue 属性,如this answer 中所述。请务必阅读最后一条声明:)

标签: swift enums


【解决方案1】:

只要你给你的枚举一个底层类型,它就会符合RawRepresentable协议。

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

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

这意味着您的枚举将自动拥有&lt; 运算符:

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 还会自动为其赋予&lt;=&gt;&gt;= 运算符(由标准库提供)。

【讨论】:

  • 或者你可以把枚举写成 enum E : Int, Comparable { .. } 有一个随机的延长线挂在那里没有意义,IMO。
  • 这种方法是否为字符串枚举返回正确的顺序(例如案例“Z”,案例“A”)?我建议,比较运算符将返回“Z”>“A”,这对我们的情况不正确。
  • 虽然在提出问题时这是一个很好的解决方案,但在我的回答 here 中使用条件一致性来做到这一点要简洁得多
【解决方案2】:

这在某种程度上与 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 评论的回应。

Comparable 不需要 ==。这是 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

【讨论】:

  • 您需要添加方法&lt;=&gt;=&gt;以符合Comparable。这是一个烦人的样板。
  • 你是对的。 Equatable 会自动添加到枚举中(除非您有一个带有变量的枚举案例)。您可以通过仅实现&lt; 来符合 Comparable。感谢您澄清这一点。 (我应该删除我上面的​​评论吗?)
  • @JasonMoore 为什么不留下您的评论以供后代参考? :-)
  • 它帮助我比较了基于字符串的枚举。工作得很好。只需要添加一个实现函数:)
【解决方案3】:

在较新版本的 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
}

【讨论】:

    【解决方案4】:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 2023-03-09
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多