Swift如何让包含协议类型属性的类型遵守Hashable/Equatable协议
最优实现方案:带Hashable能力的类型擦除器
核心解决思路是在类型擦除器中预存业务逻辑、相等判断、哈希逻辑三个闭包,既规避了协议作为属性类型无法携带Hashable约束的问题,也完全避免了你提到的两种方案的缺陷,扩展性极强。
步骤1:实现AnyFilterProcessor类型擦除器
protocol FilterProcessor { func satisfies(input: String) -> Bool } struct AnyFilterProcessor: FilterProcessor, Hashable { // 内部存储三类核心逻辑闭包 private let _satisfies: (String) -> Bool private let _equals: (Any) -> Bool private let _hash: (inout Hasher) -> Void // 初始化约束:仅接受同时遵守FilterProcessor和Hashable的具体类型 init<T: FilterProcessor & Hashable>(_ processor: T) { _satisfies = { processor.satisfies(input: $0) } _equals = { guard let other = $0 as? T else { return false } return processor == other } _hash = { hasher in processor.hash(into: &hasher) } } func satisfies(input: String) -> Bool { _satisfies(input) } static func == (lhs: AnyFilterProcessor, rhs: AnyFilterProcessor) -> Bool { lhs._equals(rhs) } func hash(into hasher: inout Hasher) { _hash(&hasher) } }
该实现利用泛型初始化的特性,在构造擦除器时就把具体类型的Hashable/Equatable逻辑捕获进闭包,外部使用时完全感知不到具体类型,也不需要给FilterProcessor协议加关联类型约束。
步骤2:调整SelectionFilter实现
protocol Filter { associatedtype Input func satisfies(input: Input) -> Bool } struct SelectionFilter: Filter, Hashable { let identifier: String // 替换原协议类型为擦除器类型 let processor: AnyFilterProcessor func satisfies(input: String) -> Bool { processor.satisfies(input: input) } // 两个属性都遵守Hashable,编译器会自动合成Equatable和Hashable实现,无需手动编码 }
步骤3:现有Processor仅需补充Hashable遵守即可
如果Processor是结构体,不需要手动写Hashable/Equatable实现,编译器会自动合成:
struct ProcessorOne: FilterProcessor, Hashable { let uuid: String let type: String func satisfies(input: String) -> Bool { // 原有业务逻辑无需修改 return false } } struct ProcessorTwo: FilterProcessor, Hashable { let data: Int func satisfies(input: String) -> Bool { // 原有业务逻辑无需修改 return false } }
步骤4:集合代码仅需加一层擦除器包装即可正常运行
Set([ SelectionFilter(identifier: "abc", processor: AnyFilterProcessor(ProcessorOne(uuid: "1234", type: "size"))), SelectionFilter(identifier: "def", processor: AnyFilterProcessor(ProcessorTwo(data: 1234))) ])
方案优势
- 扩展性极强:新增Processor类型仅需遵守
FilterProcessor & Hashable即可,不需要修改枚举、不需要继承基类,20+Processor也无额外维护成本 - 安全性高:结构体类型的Processor编译器会自动生成Hashable/Equatable实现,不存在开发者漏写的问题
- 无冗余代码:不需要针对每个Processor重复编写相等判断、哈希计算逻辑
内容的提问来源于stack exchange,提问作者tarun_sharma
相关产品推荐
相关产品推荐

