1

我有一个带有关联值的枚举,我想将其用作 RxDataSources 中的一个项目。我尝试通过将其符合 Hashable 来使其符合可识别性,如下所示

enum DriverHubWidget: Hashable, Identifiable {
    static func == (lhs: DriverHubWidget, rhs: DriverHubWidget) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
    
    var id: Int { hashValue }
    
    case greetings(DriverHubGreetingsViewModel)
    case scorecard(DriverHubScorecardSummary?, Error?)
    case optOut
    
    func hash(into hasher: inout Hasher) {
        switch self {
        case .greetings( _):
            return hasher.combine(1)
        case .scorecard( _, _):
            return hasher.combine(2)
        case .optOut:
            return hasher.combine(3)
        }
    }
}

我通过简单地为每个案例分配一个 Int 值来实现哈希函数。然后为了符合可识别,我添加了一个返回hashValue的id属性。这编译得很好。

现在,当我尝试使用它为节模型声明类型别名时,如下所示

typealias WidgetSection = AnimatableSectionModel<String, DriverHubWidget>

它确实编译并抛出错误,Type 'DriverHubWidget' does not conform to protocol 'IdentifiableType'

我不明白为什么它不起作用,当枚举符合 Hashable 和 Identifiable 时它编译得很好,但是当使用时,一致性以某种方式无效是不是因为枚举的关联值不是 Hashable?

4

2 回答 2

1

你混淆Identifiable了 Swift 内置协议IdentifiableType和 RxDataSource 库中的协议。

你可以只符合IdentifiableType.

enum DriverHubWidget: Hashable, IdentifiableType {
    
    var identity: Int {
        hashValue
    }

    ...
}

不过,你遵守的方式Hashable对我来说似乎很奇怪。您正在考虑枚举的两个值相等,只要它们是相同的大小写,而忽略它们的关联值。也就是说,.greeting(x) == .greeting(y)会是真的。这似乎相当违反直觉。如果这确实是您想要的identity,您可能只想以identity这种方式实现:

var identity: Int {
    switch self {
    case .greetings( _):
        return 1
    case .scorecard( _, _):
        return 2
    case .optOut:
        return 3
    }
}

Hashable通过实际考虑相关值来符合,或者根本不符合Hashable

于 2022-03-01T15:14:32.080 回答
0

(这不是一个完整的答案,但评论太长了。将其视为 Sweeper 已经说过的内容的附录)

对于要成为的对象Identifiable,它们需要具有将它们与其他相关对象区分开来的稳定(即不随时间变化)的身份概念。究竟哪种身份概念对您的目的有意义取决于您自己。正如文档所述

Identifiable 未指定身份的持续时间和范围。

  • 身份可以具有以下任何特征: 保证始终唯一,如 UUID。
  • 每个环境永久唯一,例如数据库记录键。
  • 在进程的生命周期中是唯一的,例如全局递增整数。
  • 在对象的生命周期内是唯一的,例如对象标识符。
  • 在当前集合中唯一,如集合索引。由协议的构造者和接收者来记录身份的性质。
  1. 您可能不想忽略身份概念中的相关值。否则,您的代码可能会尝试将两个对象视为相同,即使它们的关联值不同。

    在实践中,这意味着DriverHubGreetingsViewModel,DriverHubScorecardSummary也需要符合Identifiable. 您的Error?关联值,您可能希望将其变为(Error & Identifiable)?*

  2. 您无法精细化 to 的实现idhashValue因为哈希值(按设计)是不可预测的。完全有可能您的所有三个案例都以相同的 id 结束(如果散列以 1、2 和 3 的散列都冲突的方式播种,则会发生这种情况)

另一个注意事项:有一个可选模型,后跟一个可选错误是 Swift 中的代码异味。这是来自 Objective C 的保留,其类型系统缺乏一种轻量级的方式来表达一种另一种类型的值(“或”或“和”类型)。Swift 支持具有关联值的枚举(您已经在使用一个!),它甚至可以是通用的。标准库中已经为您内置了一个:Result<Success, Failure>

因此case scorecard(DriverHubScorecardSummary?, Error?),我建议:

case scorecard(Result<DriverHubScorecardSummary, Error & Identifiable>)
于 2022-03-01T22:08:26.763 回答