如何正确重写含List的Dart类hashCode以保证相等实例哈希一致?
正确重写包含List成员的Dart类hashCode
你的问题核心在于:Dart中List的默认hashCode是基于对象身份(内存地址)而非内容的,所以即使两个列表元素完全相同,它们的hashCode也不一样。这就导致你用Object.hash(a, b)计算的Foo实例哈希值,会因为两个实例的a、b是不同的列表对象而产生差异,哪怕内容一致。
要解决这个问题,我们需要基于列表的内容来计算哈希值,而非列表对象本身。以下是两种无需第三方包的实现方式:
方法一:使用Object.hashAll直接计算列表内容哈希
Object.hashAll可以接收一个可迭代对象,基于其中所有元素的哈希值生成一个组合哈希,完美适配列表内容的哈希计算:
class Foo { final List<int> a; final List<int> b; Foo(this.a, this.b); @override bool operator ==(Object other) => identical(this, other) || other is Foo && _listEquals(a, other.a) && _listEquals(b, other.b); @override int get hashCode => Object.hash(Object.hashAll(a), Object.hashAll(b)); // 自行实现列表相等判断,避免依赖第三方包 bool _listEquals(List<int> a, List<int> b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) return false; } return true; } }
或者更简洁的写法,把两个列表的元素合并后计算哈希:
@override int get hashCode => Object.hashAll([...a, ...b]);
注意:如果列表元素数量很大,展开列表会有轻微性能损耗,此时更推荐第一种分开计算的方式。
方法二:手动实现列表内容哈希计算
如果你想完全自定义哈希计算逻辑,可以写一个辅助函数遍历列表元素累加哈希:
class Foo { final List<int> a; final List<int> b; Foo(this.a, this.b); @override bool operator ==(Object other) => identical(this, other) || other is Foo && _listEquals(a, other.a) && _listEquals(b, other.b); // 辅助函数:计算List<int>的内容哈希 int _calculateListHashCode(List<int> list) { int hash = 17; // 初始质数,减少哈希碰撞概率 for (int num in list) { hash = 31 * hash + num.hashCode; // 31是常用的质数乘数,平衡性能和碰撞率 } return hash; } @override int get hashCode => Object.hash(_calculateListHashCode(a), _calculateListHashCode(b)); // 自行实现列表相等判断 bool _listEquals(List<int> a, List<int> b) { if (a.length != b.length) return false; for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) return false; } return true; } }
验证效果
修改后运行你的测试代码:
final list1 = Foo([0], [0]); final list2 = Foo([0], [0]); print(list1 == list2); // 输出true print(list1.hashCode == list2.hashCode); // 输出true
就能得到符合预期的结果。
内容的提问来源于stack exchange,提问作者iDecode
相关产品推荐
相关产品推荐

