Traits de igualdad
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 38 de 61.
Comparar dos instancias de una estructura personalizada con == no funciona por defecto en Rust. El compilador no sabe cómo determinar si dos estructuras son iguales; debes indicárselo implementando el PartialEq trait.
Al igual que Debug y Copy, puedes derivar PartialEq automáticamente:
#[derive(PartialEq)]
struct Coordinate {
x: i32,
y: i32,
}
let a = Coordinate { x: 5, y: 10 };
let b = Coordinate { x: 5, y: 10 };
let c = Coordinate { x: 3, y: 7 };
println!("{}", a == b); // true
println!("{}", a == c); // false
Cuando se deriva, PartialEq compara cada campo de la estructura. Dos instancias son iguales solo si todos sus campos correspondientes coinciden.
También te encontrarás con Eq, que es un rasgo marcador (marker trait) que indica igualdad total—lo que significa que cada valor es igual a sí mismo. La mayoría de los tipos cumplen con esto, pero los números de punto flotante no (porque NaN != NaN). Para estructuras con campos de enteros, puedes derivar ambos de forma segura:
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
Eq no tiene métodos propios; simplemente señala que el tipo tiene igualdad reflexiva. Algunas características de la biblioteca estándar requieren Eq además de PartialEq, por lo que es común derivar ambos juntos para los tipos que califican.
Desafío
Fácil¡Vamos a construir un sistema de coincidencia de colores que demuestre cómo los traits PartialEq y Eq permiten la comparación entre instancias de structs!
Crearás dos archivos para organizar tu lógica de comparación de colores:
color.rs: Define un structColorpúblico con tres campos públicos:red,green, yblue(todosu8). Deriva tantoPartialEqcomoEqpara que dos colores puedan compararse usando==. Al derivarlos, Rust considerará que dos colores son iguales solo si los tres componentes RGB coinciden exactamente.main.rs: Importa tu módulo de color y crea dos instancias deColorutilizando las entradas proporcionadas. Compáralas usando==e imprime si coinciden o no.
Tu salida debe indicar si los dos colores son iguales:
Color 1: rgb({r1}, {g1}, {b1})
Color 2: rgb({r2}, {g2}, {b2})
Colors match: {true/false}Por ejemplo, con las entradas 255, 128, 0, 255, 128, 0:
Color 1: rgb(255, 128, 0)
Color 2: rgb(255, 128, 0)
Colors match: trueY con las entradas 100, 100, 100, 200, 200, 200:
Color 1: rgb(100, 100, 100)
Color 2: rgb(200, 200, 200)
Colors match: falseRecibirás seis entradas: los valores RGB para el primer color (tres valores), seguidos de los valores RGB para el segundo color (tres valores). Procesa cada uno como u8.
Hoja de referencia
Para comparar structs personalizados usando ==, implementa el trait PartialEq derivándolo:
#[derive(PartialEq)]
struct Coordinate {
x: i32,
y: i32,
}
let a = Coordinate { x: 5, y: 10 };
let b = Coordinate { x: 5, y: 10 };
println!("{}", a == b); // true
Cuando se deriva, PartialEq compara todos los campos; dos instancias son iguales solo si todos los campos correspondientes coinciden.
El trait Eq es un trait marcador que indica igualdad total (cada valor es igual a sí mismo). La mayoría de los tipos cumplen con esto, excepto los números de punto flotante (porque NaN != NaN). Para structs con campos de enteros, deriva ambos traits juntos:
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
Eq no tiene métodos; señala igualdad reflexiva. Algunas características de la biblioteca estándar requieren Eq además de PartialEq.
Pruébalo tú mismo
mod color;
use color::Color;
fn main() {
// Lee los seis valores RGB
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let r1: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let g1: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let b1: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let r2: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let g2: u8 = input.trim().parse().expect("Invalid input");
input.clear();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let b2: u8 = input.trim().parse().expect("Invalid input");
// TODO: Crea dos instancias de Color usando los valores analizados
// TODO: Imprime Color 1 en el formato: Color 1: rgb(r, g, b)
// TODO: Imprime Color 2 en el formato: Color 2: rgb(r, g, b)
// TODO: Compara los dos colores usando == e imprime: Colors match: {true/false}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Métodos y Comportamiento
Intro a Bloques de ImplementaciónEl Parámetro SelfMétodos MutablesFunciones AsociadasMúltiples Bloques de ImplementaciónEncadenamiento de MétodosResumen - Acciones de Rectángulo4Proyecto: Mascota virtual
Definir la mascotaAlimentar a la mascota7Traits estándar
El trait DebugEl trait DisplayClone y CopyTraits de igualdadResumen - Punto imprimible10Proyecto: Sistema de documentos
El Trait DrawComponente de texto2Encapsulamiento y módulos
Conceptos básicos de módulosLa palabra clave PublicCampos privadosGettersSettersRepaso - Casillero seguro5Genéricos
Estructuras genéricasMétodos genéricosMúltiples tipos genéricosFunciones genéricasResumen - Punto de coordenadas8Traits como límites
Sintaxis de límites de traitsLímites múltiplesLa cláusula whereRetornar tipos con traitsResumen: Impresora genérica11Patrones de diseño en Rust
Patrón NewtypeComposiciónEl Trait DropFrom e IntoResumen - Mock de Smart Pointer3Enums avanzados
Enums con datosMétodos en EnumsCoincidencia de variantes de datosEl Enum Option revisitadoResumen - Enum Shape6Definición de Traits
¿Qué es un Trait?Implementación de TraitsImplementaciones por defectoSobrescribir valores por defectoTraits con parámetrosResumen - Reproductor multimedia