Comparar objetos en Flutter con el paquete equatable
En este artículo, vamos a ver cómo funciona la igualdad en Flutter y Dart y como el paquete Equatable nos ayuda a tener un código más limpio sin necesidad de escribir tanto código repetitivo.
Ya sabemos que si queremos comparar dos variables podemos usar el operador ==
. Por ejemplo, si queremos comparar dos cadenas de texto, el código es:
final car1 = "Toyota";
final car2 = "Toyota";
print(car1 == car2); // Resultado: true
Y si queremos comparar dos números, el código es:
final phone1 = 52123456;
final phone2 = 52123456;
print(phone1 == phone2); // Resultado: true
Veamos el resultado del código anterior en DartPad:
Comparar dos objetos de la misma clase
En los ejemplos anteriores vimos que es muy sencillo comparar dos variables usando ==
pero cuando queremos comparar dos objetos de la misma clase ya no es tan sencillo.
Si tenemos la siguiente clase:
class Car {
final String brand;
Car(this.brand);
}
Y creamos dos objetos:
final car1 = Car('Toyota');
final car2 = Car('Toyota');
print(car1 == car2); // false
A simple vista podemos decir que car1
y car2
son iguales, pero no es cierto. El resultado de comparar car1
y car2
es false
Corramos el código anterior en DartPad:
¿Porque pasa esto si todos sus valores son iguales? La respuesta es simple, en Dart por defecto el operador ==
verifica la posición en memoria y no las propiedades de cada objeto. Y ya que car1
y car2
están en posiciones de memoria diferente, el resultado de la comparación es false
.
Usando el constructor const
Utilizar el constructor const
le dice a Dart que solo debe crear una instancia de una clase para un conjunto de valores dados en tiempo de compilación. Corramos el código anterior en DartPad pero esta vez utilizando constructores const
:
Podemos ver que usar el constructor const
resuelve el problema al comparar dos objetos, pero, esto solo funciona para objetos de los cuales conocemos su valor en tiempo de compilación. No hay forma de utilizar el constructor const
en objetos creados en tiempo de ejecución. Es aquí donde entra el paquete Equatable
El paquete Equatable
Sin utilizar el paquete Equatable para comparar las propiedades de dos objetos y ver si son iguales tenemos que sobreescribir ==
y hashCode
. El codigo de la clase Car
sera:
class Car {
final String brand;
const Car(this.brand);
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Car &&
runtimeType == other.runtimeType &&
brand == other.brand;
@override
int get hashCode => brand.hashCode;
}
Equatable es un paquete que simplifica el proceso de comparar dos objetos de la misma clase sin sobreescribir ==
y hashCode
.
Internamente Equatable sobreescribe ==
y hashCode
para que nosotros no tengamos que perder tiempo escribiendo codigo repetitivo.
Utilizando Equatable el codigo anterior sera:
import 'package:equatable/equatable.dart';
class Car extends Equatable {
const Car(this.brand);
final String brand;
@override
List<Object> get props => [brand];
}
y si agregamos mas propiedades como name
el codigo sera:
class Car extends Equatable {
const Car(this.brand, this.name);
final String brand;
final String name;
@override
List<Object> get props => [brand, name];
}
Corramos el codigo en DartPad para ver el resultado:
Imporante
Hay un Bug en DartPad que no permite correr el ejemplo con Equatable. https://github.com/dart-lang/dart-pad/issues/2356
Podemos ver que el resultado es true
cuando los valores de las propiedades son los mismos. Intenta cambiando los valores de car2
¿Cuál es el resultado?
Conclusiones
El paquete Equatable es muy importante si queremos comparar dos objetos por el valor de sus propiedades, sin el tendríamos que escribir mucho código repetitivo.