Swift 5.7中any Stuff无法遵循Hashable协议的问题求助
问题:Swift 5.7中如何让
any Stuff符合Hashable以实现异构Set? 我尝试用Swift 5.7的新特性实现异构Set,简化后的Playground代码如下:
protocol Stuff: Hashable { var identifier: String { get } } struct StuffA: Stuff { let identifier: String func hash(into hasher: inout Hasher) { hasher.combine(identifier) } } struct StuffB: Stuff { let identifier: String func hash(into hasher: inout Hasher) { hasher.combine(identifier) } } var arrayOfStuff: Array<any Stuff> = [] arrayOfStuff.append(StuffA(identifier: "a")) arrayOfStuff.append(StuffB(identifier: "b")) // 运行正常 var setOfStuff: Set<any Stuff> = Set() // 错误:Type 'any Stuff' cannot conform to 'Hashable' setOfStuff.insert(StuffA(identifier: "a")) setOfStuff.insert(StuffB(identifier: "b"))
Array<any Stuff>可以正常运行,但声明Set<any Stuff>时编译器报错,无法识别any Stuff符合Hashable。已知Stuff协议继承自Hashable而非直接遵循,请问如何解决这个问题?
解决方案
方法1:在协议中显式声明Hashable核心方法
虽然Stuff继承自Hashable,但对于存在类型any Stuff,编译器需要明确的相等性判断和哈希计算逻辑。在Stuff协议中显式声明Hashable的两个核心方法,确保所有遵循类型实现统一的判断规则:
protocol Stuff: Hashable { var identifier: String { get } static func == (lhs: Self, rhs: Self) -> Bool func hash(into hasher: inout Hasher) } struct StuffA: Stuff { let identifier: String static func == (lhs: StuffA, rhs: StuffA) -> Bool { lhs.identifier == rhs.identifier } func hash(into hasher: inout Hasher) { hasher.combine(identifier) } } struct StuffB: Stuff { let identifier: String static func == (lhs: StuffB, rhs: StuffB) -> Bool { lhs.identifier == rhs.identifier } func hash(into hasher: inout Hasher) { hasher.combine(identifier) } } // 现在可正常声明并使用异构Set var setOfStuff: Set<any Stuff> = [] setOfStuff.insert(StuffA(identifier: "a")) setOfStuff.insert(StuffB(identifier: "b"))
方法2:使用类型擦除包装器
如果不想修改原协议,可创建一个类型擦除的结构体,将any Stuff包装为具体的Hashable类型:
protocol Stuff: Hashable { var identifier: String { get } } struct StuffA: Stuff { let identifier: String func hash(into hasher: inout Hasher) { hasher.combine(identifier) } } struct StuffB: Stuff { let identifier: String func hash(into hasher: inout Hasher) { hasher.combine(identifier) } } // 类型擦除包装器 struct AnyStuff: Hashable { private let base: any Stuff init(_ base: any Stuff) { self.base = base } static func == (lhs: AnyStuff, rhs: AnyStuff) -> Bool { lhs.base.identifier == rhs.base.identifier } func hash(into hasher: inout Hasher) { hasher.combine(base.identifier) } } // 通过包装器创建并使用Set var setOfStuff: Set<AnyStuff> = [] setOfStuff.insert(AnyStuff(StuffA(identifier: "a"))) setOfStuff.insert(AnyStuff(StuffB(identifier: "b")))
原理说明
Swift的存在类型any Protocol对于带有关联类型或需要具体实现的协议(如Hashable),无法自动推导其一致性。因为Hashable的相等性判断依赖明确的类型信息,而any Stuff可以是任意遵循Stuff的类型,必须显式提供统一的哈希和相等性逻辑,编译器才能认可其符合Hashable约束。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

