英文:
Strange `Set` behaviour in dart when overriding `hashCode` getter
问题
set.contains
在最后一行返回 false
,是因为在将 variable
添加到集合 set
后,你改变了 variable
的 field
值,这导致了它的哈希码发生了变化。因此,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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论