簡體   English   中英

Swift 枚舉符合可識別:類型不符合可識別協議

[英]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 標識符。
  • 在當前集合中是唯一的,如集合索引。 記錄身份的性質取決於協議的符合者和接受者。
  1. 您可能不想忽略身份概念中的相關值。 否則,您的代碼可能會嘗試將兩個對象視為相同,即使它們的關聯值不同。

    實際上,這意味着DriverHubGreetingsViewModelDriverHubScorecardSummary也需要符合Identifiable 你的Error? 關聯值,您可能想要制作成(Error & Identifiable)? *

  2. 您不能將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM