Strange `Set` behavior in Dart when overriding `hashCode` getter.

huangapple go评论64阅读模式
英文:

Strange `Set` behaviour in dart when overriding `hashCode` getter

问题

set.contains 在最后一行返回 false,是因为在将 variable 添加到集合 set 后,你改变了 variablefield 值,这导致了它的哈希码发生了变化。因此,set 不再能正确识别 variable,因为它在集合中的位置是基于其哈希码计算的,而哈希码已经不匹配了。

英文:

My code is as follows:

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
}

Why set.contains giving false in the last line?

答案1

得分: 2

默认情况下,Set 是一个 LinkedHashSet,它通过哈希码存储元素。容器无法知道元素何时发生变化并具有新的哈希码。因此,使用经过变化的元素进行后续查找将失败,因为没有具有更新的哈希码的元素存在。

教训是,您不能在 Set(以及不能在 Map 中更改键)中更改元素而不先将它们移除,然后再重新添加它们。

这也是为什么不建议为可变类覆盖 operator ==hashCode(请参考避免为可变类定义自定义相等性)。

英文:

A Set by default is a LinkedHashSet, which stores elements by hash code. The container has no way to know when an element is mutated and has a new hash code. Consequent lookups with the mutated element therefore will fail because no element exists with the updated hash code.

The moral is that you must not mutate elements in a Set (and similarly must not mutate keys in a Map) without first removing them and re-adding them after.

This also is why overriding operator == and hashCode is discouraged for mutable classes.

huangapple
  • 本文由 发表于 2023年4月11日 03:42:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980193.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定