Swift doesn't support that because Foo
instances need pattern matching, as they are not Equatable
. And the only separator that allows multiple pattern matches is ,
, and that operator corresponds to an and
operation, you can't have or
's.
One ugly (and I'd say incorrect, or misleading) approach would be to add conformance to Equatable
and ignore the associated values:
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
}
}
}
You can then do something like this:
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].contains(foo) { ... }
Another approach would be to add an index
property, and use that when testing:
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
}
}
}
And use it along the lines of
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].map({ $0.index }).contains(foo.index) { ... }
Both solutions are more verbose than the simple switch, and they would be feasible only if you need to use them many times.
Alternatively, you could extend Array
with something like this:
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
}
}
}
}
, and use it like this:
if [Foo.a(x: 0), Foo.b(x: 0), Foo.c].matchesCase(foo) { ... }
And a fourth solution :). Adding a sameCase
function:
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 }
}
}
}
Usage:
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) { ... }