How to Use a Switch Statement with a Nested Enum

How do you use a switch statement with a nested enum?

I'm adding a more general answer for a few reasons.

  1. This is the only open question regarding nested enums and switch statements. The other one is sadly closed.
  2. The only legit answer does not show how to assign the value of a nested enum to a symbol. The syntax was not intuitive to me.
  3. None of the other answers have extensive case examples.
  4. An enum nested 3 levels deep is more illustrative of the required syntax. Using efremidze answer still took me a while to work it out.

enum Action {
case fighter(F)
case weapon(W)

enum F {
case attack(A)
case defend(D)
case hurt(H)

enum A {
case fail
case success
}
enum D {
case fail
case success
}
enum H {
case none
case some
}
}
enum W {
case swing
case back
}
}

// Matches "3 deep"
let action = Action.fighter(.attack(.fail))
// Matches "1 deep" because more general case listed first.
let action2 = Action.weapon(.swing)

switch action {
case .fighter(.attack(.fail)):
print("3 deep")
case .weapon:
print("1 deep")
case .weapon(.swing):
print("2 deep to case")
case .fighter(.attack):
print("2 deep to another enum level")
default:
print("WTF enum")
}

Swift: Nested enum with switch statement

Your approach will work, you just have a few issues with your implementation. Whether or not this approach is the best way is a different issue which would depend on your requirements. I would switch to an enum with associated values for the parent if possible.

  1. Your Nested1 enum case can't have the same name as your Nested1 enum. Enum cases should start with a lowercase letter anyway so this is easy to fix.

  2. Cases for an enum with an Int raw value start at 0 by default but you want your first case to map to 1, so you need to explicitly state that.

  3. Initializing an enum with a raw value returns an optional, so you should unwrap that optional before switching on it.

Fixing these issues should give you this, which prints "Helmet" and "Iron":

enum Parent: Int {

enum Nested1: Int {
case bow = 1
case sword
case lance
case dagger
}

enum Nested2: Int {
case wooden = 1
case iron
case diamond
}

case nested1 = 1
case nested2
case case3
case case4
case case5

}

let parent = 2
let nested = 2

guard let parentCase = Parent(rawValue: parent) else {
// Do something to handle invalid enum case here
fatalError()
}

switch parentCase {
case .nested1:
print("Weapon")

case .nested2:
print("Helmet")
guard let nestedCase = Parent.Nested2(rawValue: nested) else {
// Do something to handle invalid enum case here
break
}

switch nestedCase {
case .wooden:
print("Weapon")

case .iron:
print("Iron")

case .diamond:
print("Diamond")

default:
print("")
}

default:
print("")
}

More concise way to nest enums for access by switch statements in Swift?

I think this would be much more concisely expressed with two enums and a tuple. Try this in a playground:

enum HorizontalPosition {
case Left
case Right
case Center
}

enum VerticalPosition {
case Top
case Bottom
case Center
}

typealias Location = (horizontal: HorizontalPosition, vertical: VerticalPosition)

let aLocation = Location(horizontal: .Left, vertical: .Bottom)

switch aLocation {

case (.Left, .Bottom): print ("left bottom")
case (.Center, .Center): print ("center center")
default: print ("everything else")
}

Using Switch Statement with Struct with Nested Enum - Swift

You cannot do pattern matching in the where-clause, but
you could switch on both properties of both cards instead:

switch (card.suit, card.rank, nextCard.suit, nextCard.rank) {
case (.Diamonds, .Num(5), _, .Ace):
count += 100
case (.Hearts, _, _, .Num(let n)) where n >= 3 && n % 2 != 0:
// Or: ... where [3, 5, 7, 9].contains(n):
count += n * 2
default:
break
}

Remark: According to the current Swift API Design Guidelines, enum properties should be lowercase:

Names of types and protocols are UpperCamelCase. Everything else is lowerCamelCase.

How to access second-level nested enum passed as parameter in Swift

You would need a giant switch statement to extract the cut styles,

for ingredient in salad {
let cutStyle: CutStyle?
switch ingredient {
case .lettuce(let cut):
cutStyle = cut
case .tomatoes(let cut):
cutStyle = cut
case .onions(let cut):
cutStyle = cut
case .cucumbers(let cut):
cutStyle = cut
case .dressing:
cutStyle = nil
}
print(cutStyle)
}

I think you could have modelled your salad better. Here are two alternative designs that allows you to access the cut style more easily.

One way is to make a SaladIngredient struct that composes a cut style and an ingredient:

struct SaladIngredient {
enum Ingredient {
case lettuce
case tomatoes
case onions
case cucumbers
case dressing
}

enum CutStyle {
case diced
case chopped
case minced
case grated
}

let ingredient: Ingredient
let cutStyle: CutStyle?
}
func shareSalad(my salad: [SaladIngredient]) {
print("My salad contains:")
for ingredient in salad {
if let cutStyle = ingredient.cutStyle {
print(cutStyle)
}
}
}

The disadvantage of this is that it's harder to enforce the rule that dressings don't have a cut style.

Alternatively, collapse all those enum cases with a cut style into one case:

enum SaladIngredient {
enum Ingredient {
case lettuce
case tomatoes
case onions
case cucumbers
}
enum CutStyle {
case diced
case chopped
case minced
case grated
}
case cuttable(Ingredient, cutStyle: CutStyle)
case dressing
}
func shareSalad(my salad: [SaladIngredient]) {
print("My salad contains:")
for ingredient in salad {
if case .cuttable(_, cutStyle: let cutStyle) = ingredient {
print(cutStyle)
}
}
}

The disadvantage of this is that you are making .dressing a totally different "type" of thing from lettuce, tomatoes and others.

Using enum type in a switch statement

No case labels. You've got goto labels now. Try:

switch(check){
case NEG_INF: printf("neg inf"); return 1;
case ZERO: printf("zero"); return 2;
case POS_INF: printf("pos inf"); return 3;
default: printf("not special"); break;
}

How to use an object which was given from an enum in a switch statement?

You need to declare names to bind the associated properties to instead of using _.

class ClassOne {
func something() {
print("Hello, world")
}
}

class ClassTwo {
func something2() {
print("Hello, world (2)")
}
}

enum Objects {
case classOne(ClassOne)
case classTwo(ClassTwo)
}

func loadClass(load: Objects) {
switch load {
case .classOne(let classOne): //can also be written: case let .classOne(classOne):
classOne.something()
case .classTwo(let classTwo):
classTwo.something2()
}
}

Note how I've also used the standard Swift naming convention of starting type names with capital letters and property/variable/member names with lowercase letters.

Java using enum with switch statement

The part you're missing is converting from the integer to the type-safe enum. Java will not do it automatically. There's a couple of ways you can go about this:

  1. Use a list of static final ints rather than a type-safe enum and switch on the int value you receive (this is the pre-Java 5 approach)
  2. Switch on either a specified id value (as described by heneryville) or the ordinal value of the enum values; i.e. guideView.GUIDE_VIEW_SEVEN_DAY.ordinal()
  3. Determine the enum value represented by the int value and then switch on the enum value.

    enum GuideView {
    SEVEN_DAY,
    NOW_SHOWING,
    ALL_TIMESLOTS
    }

    // Working on the assumption that your int value is
    // the ordinal value of the items in your enum
    public void onClick(DialogInterface dialog, int which) {
    // do your own bounds checking
    GuideView whichView = GuideView.values()[which];
    switch (whichView) {
    case SEVEN_DAY:
    ...
    break;
    case NOW_SHOWING:
    ...
    break;
    }
    }

    You may find it more helpful / less error prone to write a custom valueOf implementation that takes your integer values as an argument to resolve the appropriate enum value and lets you centralize your bounds checking.



Related Topics



Leave a reply



Submit