18

I'm searching for the syntax to do pattern matching with multiple cases in an if case statement. The example would be this:

enum Gender {
    case Male, Female, Transgender
}

let a = Gender.Male

Now I want to check, if a is .Male OR .Female. But I would like to avoid using switch for this. However the switch statement would be like this:

switch a {
case .Male, .Female:
    // do something
}

Is it possible to write this with if case? I would expect this, but it didn't work :(

if case .Male, .Female = a {

}
Ben
  • 3,455
  • 3
  • 26
  • 31
  • You should use a collection in js I would write something like this: `if ([Gender.Male, Gender.Female].includes(actualGender))`. – inf3rno Sep 05 '16 at 16:18
  • To my knowledge, this is not possible. I created [a feature request](https://bugs.swift.org/browse/SR-4644) a while ago. – Raphael Sep 19 '17 at 23:28

4 Answers4

31

A simple array does the trick:

if [.Male, .Female].contains(a) {
    print("Male or female")
} else {
    print("Transgender")
}

I'm simply amazed at Swift's ability to infer type. Here, it gets that .Male and .Female are of type gender from a.

Code Different
  • 90,614
  • 16
  • 144
  • 163
  • 10
    This only works if the enum is `Equatable`. An enum with an associated value for any case isn't, without manually implementing it. – rgeorge Jul 31 '17 at 18:47
  • 1
    @rgeorge You can always write a function if you need more than that. – inf3rno Sep 20 '17 at 18:02
  • 3
    @rgeorge True that the enum has to be `Equatable` - but, manual implementation is not necessary. Enums with associated values can automatically gain an implementation of `Equatable` if all of the associated value types are also `Equatable`. All you need to do is write the conformance in the declaration of the enum: `enum Gender: Equatable {`. *Note that the auto implementation is only gained if the conformance is declared in the initial declaration of the enum, not in an extension – jeremyabannister Oct 24 '18 at 17:08
2

You should use a collection. In JavaScript I would write something like this:

if ([Gender.Male, Gender.Female].includes(actualGender))
    console.log(actualGender);

Note that I have not a clue about swift, or how to do the same in that language, so here is a relevant answer in the topic: https://stackoverflow.com/a/25391725/607033 :D

EDIT: This is the Swift version:

if [.Male, .Female].contains(a) {

}
Community
  • 1
  • 1
inf3rno
  • 24,976
  • 11
  • 115
  • 197
2

If you have an associated value, you can simply create a Bool variable like this

extension Gender {

var isMaleOrFemale: Bool {
    switch self {
    case .Male, .Female:
        return true
    default:
        return false
    }
}

And usage:

if a.isMaleOrFemale { 
// Your code here
}
0

For pattern matching, what you describe will not work yet. You could do this in your case. But if it cannot be convert into a hashValue. Then this would not work either.

// Using Pattern Matching for more than one case.
if case 0...2 = a.hashValue {
    print("Hello")
}

//Normal if else
if a == .Male || a == .Female {
    print("Hello")
}
Zac Kwan
  • 5,587
  • 4
  • 20
  • 27
  • Yes, this would work, but is no pattern matching. Imagine there are more than two cases I want to check. Is there no syntax available for this purpose? – Ben Sep 05 '16 at 15:49
  • Aw, sorry i mis-read it. From what i know there is no pattern matching of what you describe. But there is a pattern that uses `hashValue` could work on your case. I will update my answer. – Zac Kwan Sep 05 '16 at 15:56
  • I don't see hashValue as an option in this case. Maybe I should better write a proposal if there is no syntax there yet :) – Ben Sep 05 '16 at 15:57
  • Ah ok, I see your point. This is not an option since the enum does not map to Int (and should not map to Int). – Ben Sep 05 '16 at 15:58
  • Currently, the only time i use a `if` for pattern matching, i only use it to map one case so i does not need to write a empty `default` in switch. Like `if case .Person(let age) = person where age <18` Other situation with more than one case that i need, i still use `switch`. – Zac Kwan Sep 05 '16 at 16:04
  • I see that using switch is much more powerful. But especially if I only want to check for one case and one case only I think it's just too much code to write with switch (and the default: break case..). – Ben Sep 05 '16 at 16:06
  • But certainly, it would be good if what you describe would work, but i don't think it will be in swift3 yet as there is no proposal for this. – Zac Kwan Sep 05 '16 at 16:06
  • That's what I should change I guess! :) – Ben Sep 05 '16 at 16:06
  • 1
    Note `==` will only work if the `enum` is `Equatable`, otherwise a `switch` statement as described in the original question is the correct approach. – Rich Sep 05 '16 at 19:44