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
相关产品推荐
相关产品推荐

