如何将枚举大小写传递给使用“if case”检查属性大小写的函数

问题描述

我有一个枚举,其中每个案例都有不同(或没有)关联值。枚举不相等。

我在多个地方使用 if case 来检查值是否属于特定情况。

enum MyEnum {
    case justACase
    case numberCase(Int)
    case stringCase(String)
    case objectCase(NonEquatableObject)
}

let myArray: [MyEnum] = [.justACase,.numberCase(100),.stringCase("Hello Enum"),.justACase]

if case .justACase = myArray[0] {
    print("myArray[0] is .justACase")
}

if case .numberCase = myArray[1] {
    print("myArray[1] is .numberCase")
}

但我想将它提取到它自己的方法中,在那里我传递我想要检查的案例。我想象如下。 (如果有什么不清楚的,请在评论中写。)

func checkCase(lhsCase: /*???*/,rhsCase: MyEnum) -> Bool {
    if case lhsCase = rhsCase {
        return true
    } else {
        return false
    }
}

// Usage:
if checkCase(lhsCase: .justACase,rhsCase: myArray[0]) {
    print("myArray[0] is .justACase")
}

在我上面的示例中,lhsCase 不应该是我假设的 MyEnum 类型,因为这意味着我会尝试比较两个属性(请参阅下面的代码)并且需要我的枚举是等价的。他们不是。

我不确定这是否可行。

如果以下方法可行,它也可以解决我的问题,但不能。

if case myArray[3] = myArray[0] {
    print("myArray[0] is .justACase")
}

解决方法

有一个库 CasePaths 可以做你想做的事:像这样:

struct NonEO {
    var a: Any
}

enum MyEnum {
    case justACase
    case numberCase(Int)
    case stringCase(String)
    case nonEO(NonEO)
}

let myArray: [MyEnum] = [.justACase,.nonEO(NonEO(a: 42)),.stringCase("Hello Enum"),.justACase,.nonEO(NonEO(a: "Thing"))]

func sameCase<T>(casePath: CasePath<MyEnum,T>,lhs: MyEnum,rhs: MyEnum) -> Bool {
    (casePath.extract(from: lhs) != nil)
        && casePath.extract(from: rhs) != nil
}

sameCase(casePath: /MyEnum.justACase,lhs: myArray[0],rhs: myArray[1]) // FALSE
sameCase(casePath: /MyEnum.justACase,rhs: myArray[3]) // TRUE

sameCase(casePath: /MyEnum.nonEO,lhs: myArray[1],rhs: myArray[4]) // TRUE
sameCase(casePath: /MyEnum.nonEO(.init(a: 42)),rhs: myArray[4]) // FALSE
,

Shadowrun 的 answer 是一个好的开始。通过 CasePaths 库,我找到了 EnumKit,这是 CasePaths 的部分灵感来源。然而,它提供了更简单的方法来比较案例。在下面查看我的实现。

使用这个库有一些不错的好处,它允许通过比较案例并忽略值来使具有关联值的枚举变得相等。这可能并不总是需要的,但在很多情况下会派上用场。我用它来比较 ReSwift Actions 和我测试中的 Associated 值。

import Foundation
import EnumKit

class NonEquatableObject {
}

enum MyEnum: CaseAccessible { // <-- conform to CaseAccessible
    case justACase
    case numberCase(Int)
    case stringCase(String)
    case objectCase(NonEquatableObject)
}

let myArray: [MyEnum] = [.justACase,.numberCase(100),.justACase]

if case .justACase = myArray[0] {
    print("myArray[0] is .justACase")
}

if case .numberCase = myArray[1] {
    print("myArray[1] is .numberCase")
}


func checkCase(lhsCase: MyEnum,rhsCase: MyEnum) -> Bool {
    if case lhsCase = rhsCase {
        return true
    } else {
        return false
    }
}

// Usage:
if checkCase(lhsCase: .justACase,rhsCase: myArray[0]) { //<-- allows to pass variables or just the cases (unfortunately not without associated value.)
    print("myArray[0] is .justACase")
}

if case myArray[3] = myArray[0] { //<-- allows this here too
    print("myArray[0] is .justACase")
}

// Bonus: Adding equatable if associated values are not equatable. Looking at the case only.
extension MyEnum: Equatable {
    static func == (lhs: MyEnum,rhs: MyEnum) -> Bool {
        lhs.matches(case: rhs)
    }
}

if myArray[3] == myArray[0] {
    print("myArray[3] == myArray[0]")
}