如何使具有关联值的Swift枚举可等于

如何使具有关联值的Swift枚举可等于

问题描述:

我有一个关联值的枚举,出于测试目的,我想使其相等,但不知道这种模式如何适用于带有多个参数的枚举案例.

I have an enum of associated values which I would like to make equatable for testing purposes, but do not know how this pattern would work with an enum case with more than one argument.

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

For example, summarised below I know the syntax for making heading equatable. How would this work for options, which contains multiple values of different types?

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

I know Swift 4.1 can synthesize conformance for Equatable for us, but at present I am not able to update to this version.

SE-0185 Synthesizing Equatable and Hashable conformance has been implemented in Swift 4.1, so that it suffices do declare conformance to the protocol (if all members are Equatable):

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

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

For earlier Swift versions, a convenient way is to use that tuples can be compared with ==.

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

You many also want to enclose the compatibility code in a Swift version check, so that the automatic synthesis is used once the project is updated to 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
}