结构体的 Swift 枚举

Posted

技术标签:

【中文标题】结构体的 Swift 枚举【英文标题】:Swift Enum of a Struct 【发布时间】: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)

【问题讨论】:

【参考方案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 很陌生,这甚至不应该用枚举来完成。

以上是关于结构体的 Swift 枚举的主要内容,如果未能解决你的问题,请参考以下文章

Swift 结构体和类的区别

Swift-类和结构体

C枚举,以及枚举和结构体的不同

Swift-类和结构体(Class and Structures)

Swift属性

Swift 结构体的使用