Wat is een goed recept voor het overschrijven van hashcode in Dart?

Ik merk dat ik hashcode en == voor een object wil overschrijven, en ik vraag me af of er best practices zijn voor het implementeren van een hashcode die afhankelijk is van meerdere attributen, en het lijkt erop dat er enkele Dart-specifieke overwegingen zijn .

Het eenvoudigste antwoord zou zijn om de hashes van alle attributen samen te XOR, en het valt waarschijnlijk niet zo erg mee. Er is ook een voorbeeld in Dart Up and Running op 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;
 }

maar dat lijkt erop dat het verwacht dat de semantiek van gehele getallen wordt afgekapt en in Dart lijkt het overlopen van het bereik van JS gehele getallen slecht voor hashing.

We zouden dat ook kunnen doen en na elke bewerking gewoon afkappen tot 32 bits.

Voor mijn toepassing is de verwachte grootte van de set erg klein en zou bijna alles kunnen, maar het verbaast me dat ik geen standaardrecept voor het algemene geval zie. Heeft iemand hier ervaring of sterke ervaring mee?


Antwoord 1, autoriteit 100%

Het quiver-pakketbiedt hulpfuncties hash2, hash3, enz., die de taak van het implementeren van hashCodevereenvoudigen, met enige zekerheid dat het correct werkt onder de Dart VM enwanneer gecompileerd naar 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);
}

Zie ook dit berichtvoor een iets langere discussie.


Antwoord 2, autoriteit 41%

In het belang van het minimaliseren van afhankelijkheden, als je al afhankelijk bent van flutter, maar niet afhankelijk bent van iets als quiver, bevat de dart:uibibliotheek hulpprogramma’s, hashValuesen hashListvoor het maken en combineren van hash-waarden. Bij het combineren van lijstwaarden moet men ervoor zorgen dat de gelijkheidsoperator en de hashcode overeenkomen. Als de hashcode de hash diep berekent, gebruik dan diepe gelijkheid, anders gebruik je oppervlakkige gelijkheid.

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);
}

Flutter API-documenten voor hashValues

Flutter API-documenten voor hashList


Antwoord 3, autoriteit 26%

Het gelijkwaardige-pakket kan helpen

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];
}

Now Person gebruikt ==en hashCodevan Equatable, waarvoor je een props-lijst nodig hebt die je geeft


Antwoord 4, autoriteit 16%

Ik beveel “gelijkwaardige” plug-in aan

https://pub.dev/packages/equatable

Voorbeeld:

Ruwe modus:

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;
}

Met gelijkwaardig :

import 'package:equatable/equatable.dart';
class Person extends Equatable {
  final String name;
  Person(this.name);
  @override
  List<Object> get props => [name];
}

Antwoord 5, autoriteit 10%

Sinds versie 2.14 heeft Dart-taal ondersteuning toegevoegd voor Object.hash(), samen met Object.hashAll()en Object.hashAllUnordered()

hash()document:

Maakt een gecombineerde hash-code voor een aantal objecten.

Voorbeeld:

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
}

Opmerking van document over implementatie:

De hash-waarde die door deze functie wordt gegenereerd, is niet gegarandeerd stabiel over verschillende uitvoeringen van hetzelfde programma, of tussen code die wordt uitgevoerd in verschillende isolaten van hetzelfde programma. Het exacte gebruikte algoritme kan verschillen tussen verschillende platforms, of tussen verschillende versies van de platformbibliotheken, en het kan afhangen van waarden die veranderen bij elke uitvoering van het programma.


Antwoord 6

Omdat Dart zo veel op Java lijkt, kun je zeker goede referenties vinden over hashCodes voor Java die ook van toepassing zijn op Dart.

Een beetje googelen bracht me naar de Wikipedia-pagina op Java’s Object.hashCode(). Heeft een heel eenvoudig voorbeeld voor de hashcode van een eenvoudig object. Een populaire methode is om een ​​vermenigvuldiging uit te voeren met een priemgetal (verschillende) en een waarde toe te voegen voor elke eigenschap van het object.

Deze vraagb.v. legt uit waarom het getal 31 is gekozen voor vermenigvuldiging voor de methode String.hashCode().

Meer gedetailleerde voorbeelden van hashcode-implementaties zijn gemakkelijk te vinden met Google.

Other episodes