DMarlon Studio

Lección 12 · 12 de 20

Operadores, == y hashCode · Dart

Defina operadores en sus clases de Dart, compare objetos por valor con == y hashCode y ordénelos con Comparable, con un tipo Money.

Dart · Operadores, == y hashCode en DMarlon Studio: el código del ejemplo y su salida en la terminal

En Dart, los operadores son métodos con un nombre especial: `operator +`, operator *, operator <… Money guarda céntimos y moneda, y define + para sumar importes (lanza ArgumentError si las monedas no coinciden), * para multiplicar por una cantidad y < para comparar. Así, coffee * 2 + croissant se lee como la cuenta de una cafetería.

Por defecto, == compara identidad: dos objetos son iguales solo si son el mismo. Para que dos Money(150) lo sean se sobrescribe `operator ==`, que recibe un Object, comprueba el tipo con is Money y compara los campos. identical sigue diciendo false: son iguales, pero no son el mismo objeto.

Regla de oro: si sobrescribe ==, sobrescriba también `hashCode`, de modo que dos objetos iguales den el mismo número. Object.hash(cents, currency) lo calcula a partir de los mismos campos que compara ==. Los Set y los Map lo usan para buscar, y por eso el conjunto {coffee, Money(150), croissant} se queda con solo dos precios.

Implementar `Comparable<Money>` con compareTo da a la clase un orden natural, y sort() lo usa sin más argumentos. toString() decide cómo se escribe el objeto, también dentro de listas y conjuntos. El último caso muestra el error al sumar euros con dólares.

Código · main.dart

class Money implements Comparable<Money> {  final int cents;  final String currency;  const Money(this.cents, [this.currency = 'EUR']);  Money operator +(Money other) {    if (other.currency != currency) throw ArgumentError('$currency + ${other.currency}');    return Money(cents + other.cents, currency);  }  Money operator *(int times) => Money(cents * times, currency);  bool operator <(Money other) => cents < other.cents;  @override  int compareTo(Money other) => cents.compareTo(other.cents); // for sort()  // Equal by value: same amount and currency. hashCode must agree with ==.  @override  bool operator ==(Object other) =>      other is Money && other.cents == cents && other.currency == currency;  @override  int get hashCode => Object.hash(cents, currency);  @override  String toString() => '${(cents / 100).toStringAsFixed(2)} $currency';}void main() {  final coffee = Money(150), croissant = Money(195);  print('Order: ${coffee * 2 + croissant}, cheaper: ${coffee < croissant}');  print('== ${Money(150) == coffee}, identical ${identical(Money(150), coffee)}');  print('Distinct prices: ${{coffee, Money(150), croissant}}'); // a Set  print('Sorted: ${[Money(999), coffee, croissant]..sort()}');  try { coffee + Money(150, 'USD'); } on ArgumentError catch (e) { print('Cannot add ${e.message}'); }}

Salida · dart run main.dart

Order: 4.95 EUR, cheaper: true
== true, identical false
Distinct prices: {1.50 EUR, 1.95 EUR}
Sorted: [1.50 EUR, 1.95 EUR, 9.99 EUR]
Cannot add EUR + USD

Para recordar

  • operator + y compañía definen operadores en sus clases.
  • Sobrescriba == para comparar por valor.
  • Con == va siempre hashCode, calculado con los mismos campos.
  • Object.hash combina varios campos en un código hash.
  • Comparable y compareTo permiten ordenar con sort().

Ejercicio

Añada operator - a Money y calcule el cambio que recibe un cliente que paga el pedido con un billete de 5 euros (Money(500)).