我有这个枚举:

enum Foo {
    case a(x: Int)
    case b(x: Int)
    case c
    case d
}

以及foo
let foo = Foo.a(x: 10)

我想检查fooab还是c,不管x是什么。
有了switch语句,我可以:
switch foo {
case .a, .b, .c:
    ...
case .d:
    break
}

但这有点冗长。
我想我也可以用if case
if case .a, .b, .c = foo { ... }

这会产生编译器错误。
然后我找到了this question,并尝试了这个:
if [Foo.a, Foo.b, Foo.c].contains(foo) { ... }

编译器认为数组的类型是[Any],所以这也不起作用。。。
除了将其提取为方法并调用该方法之外,我还能做什么?斯威夫特4.2中有什么新的东西可以解决这个问题吗?

最佳答案

Swift不支持这一点,因为Foo实例需要模式匹配,因为它们不是Equatable。唯一允许多个模式匹配的分隔符是,,并且该运算符对应于and操作,不能有or
一个丑陋的(我会说是不正确的,或误导性的)方法是将一致性添加到Equatable并忽略相关的值:

enum Foo: Equatable {
    case a(x: Int)
    case b(x: Int)
    case c
    case d

    static func ==(_ lhs: Foo, _ rhs: Foo) -> Bool {
        switch (lhs, rhs) {
        case (.a, .a): return true
        case (.b, .b): return true
        case (.c, .c): return true
        case (.d, .d): return true
        default: return false
        }
    }
}

你可以这样做:
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].contains(foo) { ... }

另一种方法是添加index属性,并在测试时使用该属性:
enum Foo {
    case a(x: Int)
    case b(x: Int)
    case c
    case d

    var index: Int {
        switch self {
        case .a: return 0
        case .b: return 1
        case .c: return 2
        case .d: return 3
        }
    }
}

并按照
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].map({ $0.index }).contains(foo.index) { ... }

这两种解决方案都比简单的开关更加冗长,而且只有在需要多次使用它们时,它们才是可行的。
或者,您可以使用以下方法扩展Array
extension Array where Element == Foo {
    func matchesCase(_ foo: Foo) -> Bool {
        return contains {
            switch ($0, foo) {
            case (.a, .a): return true
            case (.b, .b): return true
            case (.c, .c): return true
            case (.d, .d): return true
            default: return false
            }
        }
    }
}

,并像这样使用:
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].matchesCase(foo) { ... }

第四个解决方案:)。添加sameCase函数:
enum Foo {
    case a(x: Int)
    case b(x: Int)
    case c
    case d

    func sameCase(_ foo: Foo) -> Bool {
        switch self {
        // a little bit more verbose, but don't risk missing new cases
        case .a: if case .a = foo { return true } else { return false }
        case .b: if case .b = foo { return true } else { return false }
        case .c: if case .c = foo { return true } else { return false }
        case .d: if case .d = foo { return true } else { return false }
        }
    }
}

用法:
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].contains(where: foo.sameCase) { ... }
// or
if foo.sameCase(.a(x: 0)) || foo.sameCase(.b(x: 0)) || foo.sameCase(.c) { ... }

关于swift - 如何在具有关联值的枚举上与OR运算符进行模式匹配?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54159636/

10-12 14:12