简体   繁体   中英

Swift Enum of a Struct

In other languages I can construct complex enums which hold multiple values / a class / a struct for each case. This seems to be impossible in Swift. At least I could not find a simple solution. So far I came up with these possibilities which include some boilerplate and are not as elegant as I am used to from other languages.

What would be the downside of each solution? Is there something else I could do? Would a class be a better solution?

In the end I want a finite, distinct, iterable construct of immutable values. I would like that to be an enum since they usually have benefits like knowing when they were matched exhaustively.


enum CategoryEnum: Int, CaseIterable {
    case general = 9
    case tech = 5

    var value: Category? {
        switch rawValue {
        case 9:
            return Category(name: "General Knowledge", id: rawValue, symbol: Image(systemName: "globe"))
        case 5:
            return Category(name: "Technical", id: rawValue, symbol: Image(systemName: "internaldrive"))
        default:
            return nil // or throw error to ged rid of optional?
        }
    }
}

struct Category {
    static let GENERAL = Category(name: "General Knowledge", id: 9, symbol: Image(systemName: "globe"))
    static let TECH = Category(name: "Technical", id: 5, symbol: Image(systemName: "internaldrive"))

    static private let cases: [Int: Category] = [
        GENERAL.id: GENERAL,
        TECH.id: TECH
    ]

    static func fromId(_ id: Int) -> Category? {
        Category.cases[id]
    }

    static func values() -> Dictionary<Int, Category>.Values {
       cases.values
    }

    let name: String
    let id: Int
    let symbol: Image
}

func testWithEnum() {
    // iterating over all cases
    for cat in CategoryEnum.allCases {
        print(cat.value!.name)
    }

    // getting a case from the id
    let catGen = CategoryEnum(rawValue: 9)
    print(catGen!.value!.name)

    // a specific case
    print(CategoryEnum.general.value!.name)
}

func testWithStruct() {
    // iterating over all cases
    for cat in Category.values() {
        print(cat.name)
    }

    // getting a case from the id
    print(Category.fromId(9)!.name)

    // a specific case
    print(Category.TECH.name)
}

I would do:

enum Category: Int, CaseIterable {
    case general = 9
    case tech = 5
    
    var name: String {
        switch self {
        case .general: return "General Knowledge"
        case .tech: return "Technical"
        }
    }
    var symbol: Image {
        switch self {
        case .general: return Image(systemName: "globe")
        case .tech: return Image(systemName: "internaldrive")
        }
    }
}

The one thing you might not like about this is that you can't see at a glance, what name and symbol a certain enum case has, compared to your struct solution.

Note that every time you add a case to this, you won't forget to add return statements to each of the properties, because the switch statements would no longer be exhaustive and the compiler would complain.

You don't need a separate id property. That seems to be just be the raw value. init(rawValue:) is synthesised because you have a raw value, and allCases is also synthesised due to CaseIterable conformance.

What would be the downside of each solution?

Your enum solution returns an optional for its value , but clearly each case must have a Category associated with it, so it doesn't make much sense. As you can see in my code, you can switch on self to make the switch exhaustive.

Your struct solution doesn't prevent people from creating other Category s, so it's not "finite" as you wanted. You should write a private initialiser to prevent that if you want to go with a struct solution. Also, there's quite a lot of boilerplate for case and fromId . If you use an enum, those are synthesised by the compiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM