【问题标题】:Swift Enum of a Struct结构体的 Swift 枚举
【发布时间】:2021-06-05 11:03:30
【问题描述】:

在其他语言中,我可以构造复杂的枚举,它为每种情况保存多个值/一个类/一个结构。这在 Swift 中似乎是不可能的。至少我找不到一个简单的解决方案。到目前为止,我提出了这些可能性,其中包括一些样板文件,并且不像我习惯的其他语言那样优雅。

每种解决方案的缺点是什么?还有什么我可以做的吗?类会是更好的解决方案吗?

最后,我想要一个有限的、独特的、可迭代的不可变值构造。我希望这是一个枚举,因为它们通常有好处,比如知道它们何时被彻底匹配。


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)
}

【问题讨论】:

    标签: swift class struct enums


    【解决方案1】:

    我愿意:

    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")
            }
        }
    }
    

    您可能不喜欢的一件事是,与您的结构解决方案相比,您无法一眼看出某个枚举案例的名称和符号。

    请注意,每次向其中添加 case 时,都不会忘记向每个属性添加 return 语句,因为 switch 语句将不再是详尽无遗的,编译器会报错。

    您不需要单独的 id 属性。这似乎只是原始价值。 init(rawValue:) 被合成是因为你有一个原始值,allCases 也是因为 CaseIterable 一致性而被合成的。

    每种解决方案的缺点是什么?

    您的枚举解决方案为其value 返回一个可选项,但显然每个案例必须 有一个与之关联的Category,所以它没有多大意义。正如您在我的代码中看到的那样,您可以打开self 以使开关变得详尽。

    您的 struct 解决方案不会阻止人们创建其他 Categorys,因此它不是您想要的“有限”。如果您想使用结构解决方案,您应该编写一个私有初始化程序来防止这种情况。此外,casefromId 有很多样板文件。如果你使用枚举,那些是由编译器合成的。

    【讨论】:

    • 我认为这大致是我想要的,并且在语言的限制下是可能的。仍然不如其他语言优雅,但没有一种语言是完美的。感谢您帮助我。
    • @sbstnzmr 你在说什么语言能比这更有效?我现在想学那门语言:)
    • 这不是全新的,我的措辞可能是错误的。应该没有写得更强大但不同。 Swift 和 Rust 有枚举,其中枚举可以有不同的类型。例如,Java 没有它,但它们有可以封装多个值的枚举。在此示例中,我不想将 enum 与某处的 Image 匹配。我希望将该图像封装在枚举中。也许只是我对 Swift 很陌生,这甚至不应该用枚举来完成。
    猜你喜欢
    • 2017-06-14
    • 2016-11-29
    • 2015-09-23
    • 1970-01-01
    • 2020-03-08
    • 2020-08-10
    • 2019-02-07
    相关资源
    最近更新 更多