You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中能否基于objectId让Data协议通用实现Hashable?

当然可以!我们可以通过让自定义Data协议直接继承Hashable,并在协议扩展中提供默认的Equatable和Hashable实现,这样所有遵循Data的类型都会自动获得这些能力,无需重复编写冗余代码。

具体实现方案

1. 修改Data协议,让它继承Hashable

首先更新你的自定义协议,使其成为Hashable的子协议:

// 注意:这里的Data是自定义协议,避免与Foundation的Data类型混淆
public protocol Data: Hashable {
    var state: [String: Any] { get set }
    var objectId: String? { get set }
}

2. 在协议扩展中提供默认实现

在Data的扩展里,除了保留原有的objectId默认实现,再添加Equatable的==方法和Hashable的hash(into:)方法的通用实现:

public extension Data {
    // 保留原有的objectId默认实现
    var objectId: String? {
        get { return self.state["objectId"] as? String }
        set { self.state["objectId"] = newValue }
    }
    
    // 基于objectId的默认相等判断逻辑
    static func == (lhs: Self, rhs: Self) -> Bool {
        return lhs.objectId == rhs.objectId
    }
    
    // 基于objectId的默认哈希值生成逻辑
    func hash(into hasher: inout Hasher) {
        hasher.combine(self.objectId ?? "")
    }
}

3. 验证效果:遵循协议的类型无需额外代码

现在所有遵循Data的结构体(比如Person、Car)都自动满足Hashable要求,不用再为每个类型单独编写扩展:

public struct Person: Data {
    public var state: [String : Any]
}

public struct Car: Data {
    public var state: [String : Any]
}

// 可以直接使用Hashable的能力,比如放入Set或作为字典键
let person1 = Person(state: ["objectId": "123"])
let person2 = Person(state: ["objectId": "123"])
print(person1 == person2) // 输出: true

let carSet: Set<Car> = [Car(state: ["objectId": "car-001"])]

额外说明

  • 如果某个遵循Data的类型需要自定义相等或哈希逻辑,只需在该类型的扩展中覆盖==或hash(into:)方法即可,类型专属的实现会优先于协议扩展的默认实现。
  • 若担心命名冲突,可以考虑将自定义Data协议重命名(比如ModelData),避免与Foundation框架的Data类型混淆。

内容的提问来源于stack exchange,提问作者Another Dude

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 22:02:30