You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart中重写hashCode getter后Set出现异常行为的原因

问题原因分析

先看对应的代码实现:

class Foo {
  double field = 0;

  @override
  bool operator ==(Object other) {
    if (other is! Foo) return false;
    return field == other.field;
  }

  @override
  int get hashCode => field.hashCode;
}

void main() {
  final set = Set<Foo>();
  final variable = Foo();

  set.add(variable); // add variable to Set
  variable.field = 1; // change variable
  for (var v in set) print(v == variable); // true: content of the Set changed as expected
  print(set.contains(variable)); // false: I would expect true here
}

Dart里的Set是基于哈希表实现的,它的查找和存储逻辑完全依赖hashCode和==两个方法,这就是问题的核心:

  • 添加元素时:调用set.add(variable)时,Set会用当时variable的hashCode(此时field=0,对应哈希值是0的哈希码)计算存储位置,把元素存在这个位置里。
  • 修改元素后:你把variable.field改成1,由于Foo的hashCode直接绑定field的哈希值,所以这个对象的哈希码也跟着变成了1的哈希值。
  • contains的查找逻辑:调用set.contains(variable)时,Set会先用当前的新哈希码去哈希表中找对应的位置,但这个位置和当初存储元素的旧位置完全不一样,自然找不到目标元素,直接返回false。
  • 遍历比较的逻辑:而遍历Set时,是直接取出哈希表里所有元素,逐个和variable用==方法对比——此时两个对象的field都是1,==方法返回true,所以打印结果为true。

总结一下:Set找元素是先靠哈希码定位位置,再用==验证;你修改对象导致哈希码变更,Set找不到原来的存储位置,所以contains返回false,但遍历是全量逐个比较,所以能匹配成功。

内容的提问来源于stack exchange,提问作者Andrey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:23:18