具有符合 CaseIterable、RawRepresentable 的关联值的枚举

Posted

技术标签:

【中文标题】具有符合 CaseIterable、RawRepresentable 的关联值的枚举【英文标题】:Enum with associated value conforming to CaseIterable, RawRepresentable 【发布时间】:2019-03-17 21:18:14 【问题描述】:

我正在尝试使具有关联值的枚举符合 CaseIterable、RawRepresentable。在用 rawValue 初始化时,我对关联值的一些默认值很好。

enum GenresAssociated: CaseIterable, RawRepresentable, Equatable 
    case unknown(String)
    case blues(String)
    case classical(String)
    // Implementing CaseIterable
    typealias AllCases = [GenresAssociated]
    // Enums can have no storage, but the class they are in CAN. Note 'static' in declaration
    static var allCases: [GenresAssociated] = [.unknown(""), .blues(""), .classical("")]


    typealias RawValue = Int
    var rawValue: Int 

        // MARK: This causes a crash for unknown reason
        return GenresAssociated.allCases.firstIndex(where:   if case self = $0  return true  else  return false   ) ?? 0
    
    init?(rawValue: Int) 
        guard GenresAssociated.allCases.indices.contains(rawValue) else  return nil 
        self = GenresAssociated.allCases[rawValue]
    

有什么方法可以在所有情况下不手动切换,即没有这样的代码:

    typealias RawValue = Int
    var rawValue: Int 
        switch self 
        case .unknown:
            return 0
        case .blues:
            return 1
        case .classical:
            return 2
        
    

值得注意的是,非常相似的代码也可以正常工作,例如

enum EnumWithValue 
    case one(NSString!), two(NSString!), three(NSString!)


let arrayOfEnumsWithValues: [EnumWithValue] = [.one(nil), .two(nil), .three("Hey")]

if let index = arrayOfEnumsWithValues.firstIndex(where:  if case .two = $0  return true ; return false ) 
    print(".two found at index \(index)") //prints ".two found at index 1"

【问题讨论】:

我不会在具有关联值的枚举上使用RawRepresentable,正如RawRepresentable 协议所表明的那样,您可以“在自定义类型和关联的 RawValue 类型之间来回切换而不会丢失原始 RawRepresentable 类型的值” (developer.apple.com/documentation/swift/rawrepresentable)。这意味着您的关联值也以某种方式包含在 rawValue 中。 完全同意,@Palle。数据结构是一种 kext(也是 Enum 的压力测试)。是的,我在这里玩 Enums,试图掌握它们。 【参考方案1】:

我终于可以和Mirror一起工作了!

var rawValue: Int 
    let selfCaseName = Mirror(reflecting: self).children.first!.label!

    return GenresAssociated.allCases.firstIndex(where:  (genre) in
        let switchingCaseName = Mirror(reflecting: genre).children.first!.label!

        return switchingCaseName == selfCaseName
    )!

不要介意强行展开,这里很安全。

【讨论】:

绝对是一个可行的解决方案,@J。能源部。我有时也会使用 Mirror 作为最后的手段。但我也在试图找出我的语法有什么问题,即我是在创建内存循环还是遇到了懒惰或故障等问题。 能否请您添加一些有关其工作原理/原因的更多详细信息。这有可能成为一个非常受欢迎(高度赞成)和有用的答案。谢谢【参考方案2】:

此参数适用于包含 rawValue 案例和关联值案例的枚举:

var caseName: String  
   let result = String(describing: self)
   let assocValName = Mirror(reflecting: self).children.first?.label ?? "failed"

   return !result.contains("(") ? result : assocValName

【讨论】:

以上是关于具有符合 CaseIterable、RawRepresentable 的关联值的枚举的主要内容,如果未能解决你的问题,请参考以下文章

由枚举驱动的 SwiftUI 选择器:值未更新

如何使具有泛型属性的结构符合可等式?

返回的对象具有符合 Mongoose 条件的嵌套值

Swift:具有符合协议的实例的完成闭包

具有直接 QueryPerformanceCounter 值的时钟可以符合 C++ 标准吗?

具有泛型的Swift函数,其中约束是自身符合的协议