在Dart中覆盖哈希码的好方法是什么?

Ala*_*ght 25 hashcode dart

我发现自己想要覆盖一个对象的哈希码和==,我想知道是否有关于如何实现依赖于多个属性的哈希码的最佳实践,并且似乎有一些特定于Dart的注意事项.

最简单的答案是将所有属性的哈希值混合在一起,这可能不是太糟糕.在Dart Up和Running中也有一个例子,网址是https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html

  // Override hashCode using strategy from Effective Java, Chapter 11.
 int get hashCode {
   int result = 17;
   result = 37 * result + firstName.hashCode;
   result = 37 * result + lastName.hashCode;
   return result;
 }
Run Code Online (Sandbox Code Playgroud)

但似乎它期望截断整数语义,并且在Dart中溢出JS整数的范围似乎不适合散列.

我们也可以这样做,并在每次操作后截断为32位.

对于我的应用程序,预期的集合大小非常小,几乎任何事情都可以,但我很惊讶没有看到一般情况的标准配方.有没有人有这方面的经验或经验?

man*_*nta 81

从 2.14 版本开始,Dart 语言添加了对Object.hash(), 以及Object.hashAll()和 的支持Object.hashAllUnordered()

hash()文档:

为多个对象创建组合哈希码。

例子:

class SomeObject {
  final Object a, b, c;
  SomeObject(this.a, this.b, this.c);

  bool operator==(Object other) =>
      other is SomeObject && a == other.a && b == other.b && c == other.c;

  int get hashCode => Object.hash(a, b, c); // <----- here
}
Run Code Online (Sandbox Code Playgroud)

文档关于实施的注释:

不能保证此函数生成的哈希值在同一程序的不同运行中或在同一程序的不同隔离区中运行的代码之间保持稳定。所使用的确切算法可能在不同平台之间或不同版本的平台库之间有所不同,并且可能取决于每次程序执行时更改的值。

  • 这应该赞成。这是推荐的方法:https://dart.dev/guides/libraries/library-tour#implementing-map-keys (9认同)

Pat*_*lin 29

颤动提供了辅助功能hash2,hash3等等,这简化了实现的任务hashCode,一些保证其正常运行下达特VM 当编译为JavaScript.

import 'package:quiver/core.dart';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  bool operator ==(o) => o is Person && name == o.name && age == o.age;
  int get hashCode => hash2(name.hashCode, age.hashCode);
}
Run Code Online (Sandbox Code Playgroud)

另请参阅此帖子以进行稍微冗长的讨论.

  • 从 Dart 2.14 开始,您可以使用“Object.hash()”:https://dart.dev/guides/libraries/library-tour#implementing-map-keys。请参阅马尼坎塔的回答。 (9认同)
  • `hash2(name,age)` 还不够吗? (2认同)

Pav*_*vel 17

equatable包可以帮助

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  final String name;
  final int age;

  Person(this.name, this.age);

  @override
  List<Object> get props => [name, age];
}
Run Code Online (Sandbox Code Playgroud)

现在 Person 将使用Equatable 中的==hashCode,它需要props您提供的列表

  • @NiklasLehnfeld 如果你需要扩展另一个类,你可以使用 mixin。例如 `class MyModel 使用 EquatableMixin 扩展 ChangeNotifier` (2认同)

Dan*_*ton 17

为了最小化依赖关系,如果您已经依赖 flutter,但不依赖于类似的东西quiverdart:ui库包含实用程序,hashValues以及hashList用于创建和组合哈希值。如果组合列表值,必须小心确保相等运算符和哈希码匹配行为。如果哈希码计算它的哈希值很深,则使用深度相等,否则使用浅相等。

class Example {
    final String value1;
    final Object value2;
    final List<Object> deep;
    final List<Object> shallow;

    Example({this.value1, this.value2, this.deep, this.shallow});

    @override
    operator ==(o) =>
        o is Example &&
        o.value1 == value1 &&
        o.value2 == value2 &&
        listEquals(o.deep, deep) &&
        o.shallow == shallow;

    @override
    int get hashCode => hashValues(value1, value2, hashList(deep), shallow);
}
Run Code Online (Sandbox Code Playgroud)

hashValues 的 Flutter API 文档

hashList 的 Flutter API 文档

  • 请注意,现在 hashValues 和 hashList 均已弃用。使用 Object.hashAll() 和 Object.hashAllUnordered() 代替:https://api.flutter.dev/flutter/dart-ui/hashList.html (5认同)
  • 太棒了,最小化依赖性始终符合我的兴趣! (3认同)

Joa*_*ido 11

我推荐“等效”插件

https://pub.dev/packages/equatable

例子:

原始模式:

class Person {
  final String name;

  const Person(this.name);

  @override
  bool operator ==(Object other) =>
    identical(this, other) ||
    other is Person &&
    runtimeType == other.runtimeType &&
    name == other.name;

  @override
  int get hashCode => name.hashCode;
}
Run Code Online (Sandbox Code Playgroud)

与等同:

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  final String name;

  Person(this.name);

  @override
  List<Object> get props => [name];
}
Run Code Online (Sandbox Code Playgroud)