自定义Hashable类型存入Set时相等判断未触发,如何修复?
问题解答
为什么自定义相等判断函数未被调用?
Swift中Set基于哈希表实现,元素插入/查找遵循以下逻辑:
- 先计算待插入元素的哈希值,定位到对应的哈希桶
- 仅当目标哈希桶中已有元素时,才会调用
==方法比较元素是否相等
你的NumberPair中,(1,2)和(2,1)的哈希值不同——因为hash(into:)按n1→n2的顺序组合哈希,交换数值顺序后哈希结果必然不同。这两个元素会被分配到不同哈希桶,Set不会触发==方法比较。但根据你的==实现,这两个元素是相等的,违反了Hashable协议的核心规则:所有相等的实例必须拥有完全相同的哈希值。当Set检测到存在相等但哈希值不同的元素时,就会抛出运行时错误。
正确的实现方式
需要调整hash(into:)方法,确保所有逻辑相等的NumberPair实例产生相同哈希值。最简单的方式是基于n1和n2的最小值、最大值组合哈希,消除顺序影响:
struct NumberPair: Hashable { let n1: Int let n2: Int static func == (lhs: NumberPair, rhs: NumberPair) -> Bool { (lhs.n1 == rhs.n1 && lhs.n2 == rhs.n2) || (lhs.n2 == rhs.n1 && lhs.n1 == rhs.n2) } func hash(into hasher: inout Hasher) { // 用最小值和最大值组合,保证顺序不影响哈希结果 hasher.combine(min(n1, n2)) hasher.combine(max(n1, n2)) } }
修改后,(1,2)和(2,1)的哈希值完全相同,插入Set时会触发==方法比较,确认二者相等,最终Set中仅保留一个元素,符合预期。
内容的提问来源于stack exchange,提问作者Reinhard Männer
相关产品推荐
相关产品推荐

