![](/img/trans.png)
[英]Swift Value of protocol type 'XXX' cannot conform to 'Identifiable'; only struct/enum/class types can conform to protocols
[英]Swift enum conformance to identifiable: Type doesn't conform to Identifiable protocol
我有一个具有关联值的枚举,我想将其用作 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 值来实现哈希 function。 然后为了符合可识别性,我添加了一个返回哈希值的 id 属性。 这编译得很好。
现在,当我尝试使用它为 model 部分声明类型别名时,如下所示
typealias WidgetSection = AnimatableSectionModel<String, DriverHubWidget>
它确实编译并抛出错误, Type 'DriverHubWidget' does not conform to protocol 'IdentifiableType'
我不明白为什么它不起作用,当枚举符合 Hashable 和 Identifiable 时它编译得很好,但是当使用时一致性不知何故无效是因为枚举的关联值不是 Hashable 吗?
您将 Swift 内置协议Identifiable
与 RxDataSource 库中的协议IdentifiableType
混淆了。
您可以只符合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
。
(这不是一个完整的答案,但评论太长了。将其视为 Sweeper 已经说过的内容的附录)
对于可Identifiable
的对象,它们需要有一个稳定的(即不随时间改变)身份概念,以将它们与其他相关对象区分开来。 究竟哪种身份概念对您的目的有意义取决于您。 正如文档中提到的:
Identifiable 未指定身份的持续时间和 scope。
- 身份可以具有以下任何特征: 保证始终唯一,如 UUID。
- 每个环境持久唯一,如数据库记录键。
- 在进程的生命周期内是唯一的,例如全局递增整数。
- 在 object 的生命周期内是唯一的,例如 object 标识符。
- 在当前集合中是唯一的,如集合索引。 记录身份的性质取决于协议的符合者和接受者。
您可能不想忽略身份概念中的相关值。 否则,您的代码可能会尝试将两个对象视为相同,即使它们的关联值不同。
实际上,这意味着DriverHubGreetingsViewModel
、 DriverHubScorecardSummary
也需要符合Identifiable
。 你的Error?
关联值,您可能想要制作成(Error & Identifiable)?
*
您不能将id
的实现细化为hashValue
,因为 hash 值(按设计)是不可预测的。 您的所有三个案例完全有可能以相同的 id 结束(如果散列的播种方式是 1、2 和 3 的散列都发生冲突,则会发生这种情况)
另一个注意事项:有一个可选的 model,后面跟着一个可选的错误是 Swift 中的代码味道。这是从目标 C 中保留下来的,其类型系统缺乏一种轻量级的方式来表达一种或另一种类型的值(“或”或“求和”类型)。 Swift 支持具有关联值的枚举(您已经在使用一个。)它甚至可以是通用的:标准库中已经为您内置了一个: Result<Success, Failure>
因此,而不是case scorecard(DriverHubScorecardSummary?, Error?)
,我建议:
case scorecard(Result<DriverHubScorecardSummary, Error & Identifiable>)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.