![](/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.