Swift 如何对带有参数的枚举执行if-else比较

Swift 如何对带有参数的枚举执行if-else比较,swift,enums,Swift,Enums,语言:Swift2.3 例如,我将向您展示不同类型的枚举 enum Normal { case one case two, three } enum NormalRaw: Int { case one case two, three } enum NormalArg { case one(Int) case two, three } 开关可用于所有三个枚举,如下所示: var normal: Normal = .one var norm

语言:Swift2.3

例如,我将向您展示不同类型的枚举

enum Normal {
    case one
    case two, three
}

enum NormalRaw: Int {
    case one
    case two, three
}

enum NormalArg {
    case one(Int)
    case two, three
}   
开关
可用于所有三个枚举,如下所示:

var normal: Normal = .one
var normalRaw: NormalRaw = .one
var normalArg: NormalArg = .one(1)

switch normal {
    case .one: print("1")
    default: break
}

switch normalRaw {
    case .one: print(normalRaw.rawValue)
    default: break
}

switch normalArg {
    case .one(let value): print(value)
    default: break
}
在if-else语句中,虽然我只能对
Normal
NormalRaw
进行比较,但是
NormalArg
会显示一条错误消息,因此我无法运行代码

二进制运算符“==”不能应用于
NormalArg
和<代码>\

下面是代码示例:

if normal == .two { // no issue
    .. do something
}

if normalRaw == .two { // no issue
    .. do something
}

if normalArg == .two { // error here (the above message)
    .. do something
}

if normalArg == .one(_) { // error here (the above message)
    .. do something
}

if normalArg == .three { // error here (the above message)
    .. do something
}

有什么想法吗?我并不是真的在用这段代码做什么,我只是想知道为什么我们不能做比较。

答案是平等协议

现在让我们看看它是如何工作的

以该枚举为例:

enum Barcode {
    case upca(Int, Int)
    case qrCode(String)
    case none
}
如果我们检查枚举上的可等式运算符
=
,它将失败

// Error: binary operator '==' cannot be applied to two Barcode operands
Barcode.qrCode("code") == Barcode.qrCode("code")
如何使用Equalable协议修复此问题

extension Barcode: Equatable {
}

func ==(lhs: Barcode, rhs: Barcode) -> Bool {
    switch (lhs, rhs) {
    case (let .upca(codeA1, codeB1), let .upca(codeA2, codeB2)):
        return codeA1 == codeA2 && codeB1 == codeB2

    case (let .qrCode(code1), let .qrCode(code2)):
        return code1 == code2

    case (.None, .None):
        return true

    default:
        return false
    }
}

Barcode.qrCode("code") == Barcode.qrCode("code") // true
Barcode.upca(1234, 1234) == Barcode.upca(4567, 7890) // false
Barcode.none == Barcode.none // true

诀窍是不要实际使用==进行检查,而是在if语句中结合使用
case
关键字和单个=。这在开始时有点违反直觉,但就像让你很快习惯它一样:

enum Normal {
    case one
    case two, three
}

enum NormalRaw: Int {
    case one = 1
    case two, three
}

enum NormalArg {
    case one(Int)
    case two, three
}


let normalOne = Normal.one
let normalRawOne = NormalRaw.one
let normalArgOne = NormalArg.one(1)

if case .one = normalOne {
    print("A normal one") //prints "A normal one"
}

if case .one = normalRawOne {
    print("A normal \(normalRawOne.rawValue)") //prints "A normal 1"
}

if case .one(let value) = normalArgOne {
    print("A normal \(value)") //prints "A normal 1"
}
关键是,在Swift中,如果枚举使用原始类型或没有关联的值,则只能免费获得枚举方程(请尝试,不能同时拥有这两个值)。然而,Swift不知道如何将案例与相关值进行比较——我的意思是,它怎么可能?让我们看看这个例子:

Normal.one == .one //true
Normal.one == .two //false

NormalRaw.one == .one //true
NormalRaw.one == .two //false

NormalArg.one(1) == .one(1) //Well...?
NormalArg.one(2) == .one(1) //Well...?
NormalArg.one(1) == .two //Well...?
也许这更清楚地说明了为什么这不能开箱即用:

class Special {
    var name: String?
    var special: Special?
}

enum SpecialEnum {
    case one(Special)
    case two
}

var special1 = Special()
special1.name = "Hello"

var special2 = Special()
special2.name = "World"
special2.special = special1

SpecialEnum.one(special1) == SpecialEnum.one(special2) //Well...?
因此,如果您想要具有关联值的枚举,您必须自己在枚举中实现Equalatable协议:

enum NormalArg: Equatable {
    case one(Int)
    case two

    static func ==(lhs: NormalArg, rhs: NormalArg) -> Bool {
        switch (lhs, rhs) {
        case (let .one(a1), let .one(a2)):
            return a1 == a2
        case (.two,.two):
            return true
        default:
            return false
        }
    }
}

我不知道我可以在if语句中添加
case
关键字。哦,对不起,我一定是误解了你。关键是swift不知道在默认情况下,如果枚举有关联的值(原始值)。如果您的枚举没有关联的值,或者它有一个原始值类型,那么您可以通过标准库(我想是通过RawRepresentable协议)免费获得等式。您肯定知道,您不能将关联的值枚举与原始类型混合,这就是为什么您不能在协议上自行实现equalable的情况下比较“.one(Int)=.two”。从Swift 4.1开始,Swift还支持为带有关联值的枚举合成
equalable
Hashable
。读(写)起来非常糟糕,但它可以工作。非常感谢。我不知道是谁想到了这个语法(如果case.option=enum),但它很可怕,IDE甚至无法猜出您要检查哪个枚举来给u个选项,如果您不知道这个枚举的选项,您将不得不深入挖掘并浪费大量时间。这是一个很好的修复,但我将使用xxtesaxx的答案,因为它更简单。