【问题标题】:How to make a Swift enum with associated values equatable如何使关联值相等的 Swift 枚举
【发布时间】:2018-12-20 08:37:05
【问题描述】:

我有一个关联值的枚举,为了测试目的,我想使其相等,但不知道这种模式如何处理具有多个参数的枚举案例。

例如,总结如下,我知道使标题相等的语法。对于包含不同类型的多个值的选项,这将如何工作?

enum ViewModel {
    case heading(String)
    case options(id: String, title: String, enabled: Bool)
}

func ==(lhs: ViewModel, rhs: ViewModel) -> Bool {
    switch (lhs, rhs) {
    case (let .heading(lhsString), let .heading(rhsString)):
        return lhsString == rhsString
    case options...
    default:
        return false
    }
}

我知道 Swift 4.1 可以为我们综合 Equatable 的一致性,但目前我无法更新到这个版本。

【问题讨论】:

    标签: swift enums equatable associated-value


    【解决方案1】:

    处理关联值的优雅方式(即使枚举是间接的):

    首先您需要拥有value 属性:

    indirect enum MyEnum {
        var value: String? {
            return String(describing: self).components(separatedBy: "(").first
        }
        case greeting(text: String)
        case goodbye(bool: Bool)
        case hey
        case none
    }
    
    print(MyEnum.greeting(text: "Howdy").value)
    // prints : greeting
    

    现在您可以像这样使用value 来实现Equatable

        indirect enum MyEnum: Equatable {
         static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
            lhs.value == rhs.value
         }
        
         var value: String? {
            return String(describing: self).components(separatedBy: "(").first
         }
         case greeting(text: String)
         case goodbye(bool: Bool)
         case hey
         case none
       }
    

    【讨论】:

      【解决方案2】:

      SE-0185 Synthesizing Equatable and Hashable conformance 已在 Swift 4.1 中实现,因此足以声明符合协议(如果所有成员都是Equatable):

      enum ViewModel: Equatable {
          case heading(String)
          case options(id: String, title: String, enabled: Bool)
      }
      

      对于早期的 Swift 版本,一种方便的方法是使用 tuples 可以与 == 进行比较。

      许多人还希望将兼容性代码包含在 Swift 版本检查中,以便在项目更新到 Swift 4.1 后使用自动综合:

      enum ViewModel: Equatable {
          case heading(String)
          case options(id: String, title: String, enabled: Bool)
          
          #if swift(>=4.1)
          #else
          static func ==(lhs: ViewModel, rhs: ViewModel) -> Bool {
              switch (lhs, rhs) {
              case (let .heading(lhsString), let .heading(rhsString)):
                  return lhsString == rhsString
              case (let .options(lhsId, lhsTitle, lhsEnabled), let .options(rhsId, rhsTitle, rhsEnabled)):
                  return (lhsId, lhsTitle, lhsEnabled) == (rhsId, rhsTitle, rhsEnabled)
              default:
                  return false
              }
          }
          #endif
      }
      

      【讨论】:

      • 只有当所有案例都有关联的值时才成立。如果由于某种原因并非所有情况都有关联值,那么您需要使用 func == (l, r) -> bool 方法。
      • @PascaleBeaulac:不,我不认为这是真的。
      • 试试吧。我知道我在代码中有这样的情况并使用 swift 5。我需要按照 Mehrdad 在下面发布的操作来消除错误。仅添加 Equatable 不起作用。你得到它不符合 Equatable 的错误,你需要添加存根。如果所有案例都像您的示例中那样具有关联的价值,那么是的,它确实有效。
      • @PascaleBeaulac:无法复制。 enum Foo : Equatable { case bar; case baz(String) } 编译对我来说没有问题。
      • @PascaleBeaulac:SSO 是否符合 Equatable 协议?
      【解决方案3】:

      可能与 OP 无关,但这可能对其他人有所帮助:

      请记住,如果您只想比较枚举值与固定值,您可以简单地使用模式匹配:

      if case let ViewModel.heading(title) = enumValueToCompare {
        // Do something with title
      }
      

      如果关心关联值,可以在上面加一些条件:

      if case let ViewModel.heading(title) = enumValueToCompare, title == "SomeTitle" {
        // Do something with title
      }
      

      【讨论】:

        【解决方案4】:

        您可以添加如下内容,查看this link 了解更多信息。 选项的返回声明取决于您的需要。

        #if swift(>=4.1)
        #else
        func ==(lhs: ViewModel, rhs: ViewModel) -> Bool {
            switch (lhs, rhs) {
            case (let .heading(lhsString), let .heading(rhsString)):
                return lhsString == rhsString
        
            case (let .options(id1, title1, enabled1),let .options(id2, title2, enabled2)):
                return id1 == id2 && title1 == title2 && enabled1 == enabled2
            default:
                return false
            }
        }
        #endif
        

        【讨论】:

        • 需要static func
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多