Binding enums in a switch case

Purely motivated by academic reasons, is there a way I can avoid the if let binding and do something like the second (invalid) snippet?

This does what I want

enum SomeEnum: String { case a, b, c }

for i in ["a", "bb", "b", "c", "cc"] {
    if let x = SomeEnum(rawValue: i) {
        switch x {
        case .a: print(x)
        case .b: print(x)
        case .c: print(x)
        }
    }
}

This is invalid syntax, but I want to do something similar to this.

enum SomeEnum: String {case a, b, c}

for i in ["a", "bb", "b", "c", "cc"] {
    switch SomeEnum(rawValue: i) {
        case let x as .a?:
            print(x)
        case let x as .b?:
            print(x)
        case let x as .c?:
            print(x)
        case nil: print("no match")
    }
}

PS: For the sake of this discussion, disregard what the cases do with the enum instance, I am interested in being able to refer the enum instance inside the case statements. :slightly_smiling_face:

2 Likes

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations/#Matching-Enumeration-Values-with-a-Switch-Statement

Thanks for responding, not sure I understand, but I want to bind them not just match, my second snippet is basically a variant of what you linked, I did go through that link.

for i in ["a", "bb", "b", "c", "cc"] {
  switch SomeEnum(rawValue: i) {
  case let x? where x == .a:
    print(x)
  case let x? where x == .b:
    print(x)
  case let x? where x == .c:
    print(x)
  default: print("no match")
  }
}

I would still prefer the one involving if let though.

2 Likes

Usually binding is used to extract associated values (the following paragraph in the link). You don't really need bindings to match the entire value - you can just store it before the matching:

enum SomeEnum: String {case a, b, c}

for i in ["a", "bb", "b", "c", "cc"] {
    if let x = SomeEnum(rawValue: i) 
        switch x {
        case .a:
            print(x)
        case .b:
            print(x)
        case .c:
            print(x)
        }
    } else { 
        print("no match")
    }
}

I am not sure if my question was clear :upside_down_face: , this is exactly my first snippet? As I mentioned, I wanted to know how I can avoid that.

@xAlien95 has shown one such solution. Thanks

Why do you want to avoid it? What is wrong with it?

Literally the first line in my question, I do not mean to sound rude, but your replies are basically in my question.

My apologies. I misread you question twice and my replies were indeed not helpful at all. Cannot think of anything better than @xAlien95 suggested.

2 Likes

Apologies if I were rude or snarky :slight_smile: thanks for taking your time to respond and clarify.

You could make the conversion and Optional case match on the first line, then you'd be left with just a SomeEnum value inside the loop:

enum SomeEnum: String { case a, b, c }

for case let x? in ["a", "bb", "b", "c", "cc"].map(SomeEnum.init(rawValue:)) {
    switch x {
    case .a: print(x)
    case .b: print(x)
    case .c: print(x)
    }
}
4 Likes

I think what your are looking for is case .none:

func foo(x: SomeEnum?) {
    switch x {
    case .a: // …
    // case …
    case .none: // …
    }
}

Swift allows to expand optionals as switch with, in case of enum, with all its cases + .none from Optional.

2 Likes

Alternatively, you could use compactMap:

for x in ["a", "bb", "b", "c", "cc"].compactMap(SomeEnum.init(rawValue:)) {
  switch(x) {
  ...
  }
}
5 Likes

I think you mean compactMap but good point.

1 Like

Thanks, fixed now.

The other answers here are good, but there is no way to replicate what these two lines are doing, without if, guard, or another switch. Swift has no mechanism to bind a variable for further usage without them.

guard was created explicitly for this.

for i in ["a", "bb", "b", "c", "cc"] {
  guard let x = SomeEnum(rawValue: i) else {
    print("no match")
    continue
  }

  switch x {
  case .a:
    print(x)
  case .b:
    print(x)
  case .c:
    print(x)
  }
}
["a", "bb", "b", "c", "cc"].forEach { i in
  guard let x = SomeEnum(rawValue: i) else {
    print("no match")
    return
  }

  switch x {
  case .a:
    print(x)
  case .b:
    print(x)
  case .c:
    print(x)
  }
}
for i in ["a", "bb", "b", "c", "cc"] {
  switch SomeEnum(rawValue: i) {
  case let x?:
    switch x {
    case .a:
      print(x)
    case .b:
      print(x)
    case .c:
      print(x)
    }
  case nil: print("no match")
  }
}
2 Likes