如何使Swift枚举与相关值相等

s5a0g9ez  于 2023-05-27  发布在  Swift
关注(0)|答案(5)|浏览(131)

我有一个关联值的枚举,我想使其可等同以用于测试目的,但不知道此模式如何处理具有多个参数的枚举情况。
例如,下面总结了我知道使标题相等的语法。对于包含多个不同类型值的选项,这将如何工作?

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的一致性,但目前我无法更新到这个版本。

b0zn9rqh

b0zn9rqh1#

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

a9wyjsp72#

使用关联值的优雅方式(即使枚举是间接的):
首先你需要有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
   }
but5z9lq

but5z9lq3#

您可以添加如下内容,请查看this link以获取更多信息。选项的Return语句取决于您的需要。

#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
ymdaylpp

ymdaylpp4#

也许这与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
}
qgelzfjb

qgelzfjb5#

在原始的解决方案中,如果你只想比较枚举的情况,而不想比较它们的关联值,有一段代码可以简化,下面是更新后的代码:

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 (.heading, .heading), (.options, .options):
           return true
       default:
           return false
        }
     }
    #endif
 }

   let model1 = ViewModel.options(id: "1", title: "hello", enabled: true)
   let model2 = ViewModel.options(id: "2", title: "hello", enabled: true)
   let model3 = ViewModel.options(id: "1", title: "hello", enabled: true)

   print(model1 == model2) // false
   print(model1 == model3) // true

相关问题