Dart:类生成的hashCode

时间:2017-09-14 14:18:05

标签: dart hashcode

我有一个新类的奇怪行为,我必须覆盖==运算符和hashCode方法。

我会以你为榜样。 假设我们有一个如下所示的Test类:

import 'package:quiver/core.dart';
import 'package:collection/collection.dart';

class Test {

  List testList = [];

  operator ==(Object other) {
    if (other is! Test) return false;
    Function deepEq = const DeepCollectionEquality.unordered().equals;
    return deepEq(testList, (other as Test).testList);
  }

  int get hashCode => hashObjects(testList);
}

现在我运行以下代码:

main() {
  Test test = new Test();
  //test.testList.add([]);
  print('Test,  hash: ${test.hashCode}');
  Test test_2 = new Test();
  //test_2.testList.add([]);
  print('Test_2,  hash: ${test_2.hashCode}');
  print("is ${test == test_2} that Test and Test2 are equal");
  Function deepEq = const DeepCollectionEquality.unordered().equals;
  bool b = deepEq(test, test_2);
  print("is $b that Test and Test2 are deep equal");

  List l1 = [test];
  print('L1 hash: ${l1.hashCode}');
  List l2 = [test_2];
  print('L2 hash: ${l2.hashCode}');
  deepEq = const DeepCollectionEquality.unordered().equals;
  b = deepEq(l1, l2);
  print("is $b that List1 and List2 are deep equal");
}

上面的代码打印出以下内容,这就是我的预期:

Test,  hash: 0 
Test_2,  hash: 0 
is true that Test and Test2 are equal
is true that Test and Test2 are deep equal 
L1 hash: 89819481 
L2 hash: 414841104 
is true that List1 and List2 are deep equal

现在如果我取消注释行:

  test.testList.add([]);
  test_2.testList.add([]);

并重新运行程序,我有以下结果:

Test,  hash: 76603616
Test_2,  hash: 386421917
is true that Test and Test2 are equal
is true that Test and Test2 are deep equal
L1 hash: 915458568
L2 hash: 503799923
is false that List1 and List2 are deep equal

这不是我的预期。鉴于DeepCollectionEquality在内部使用hashCode来检查相等性,我可以理解,当遇到List作为主List的组件时,hashObjects使用List hashCode,而不是生成一个读取所有组件的新的hashCode。我不明白为什么测试和测试2被认为是等于List1和List2不是。 这取决于我正在创建哈希码的Iterable中存在多少级内部列表? HashObjects的设计工作方式与此类似,或者应该将其视为错误? 我如何使用hashObjects有什么问题吗?

1 个答案:

答案 0 :(得分:0)

你的问题是hashObjects()没有递归,而且空列表的两个不同实例通常会有不同的哈希值(除非两者都是常量或偶然)。

因此,hashObjects()的工作方式与平面列表相同,但不适用于列表列表,除非相应的子列表是相同的对象(并且不仅仅是结构上相同的)。

以下示例应说明这一点:

import 'package:quiver/core.dart';

void main() {
  var a = [];
  var b = [];
  var c = [];
  print(a.hashCode); // different
  print(b.hashCode);
  print(hashObjects(a)); // both same, both zero
  print(hashObjects(b));
  print(hashObjects(a..add(1))); // both same
  print(hashObjects(b..add(1)));
  print(hashObjects(a..add(c))); // both same, because `c` is identical
  print(hashObjects(b..add(c)));
  print(hashObjects(a..add([]))); // different, because the two empty
  print(hashObjects(b..add([]))); // lists are not identical.
}