Les traits d'égalité
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 38 sur 61.
Comparer deux instances d'une structure personnalisée avec == ne fonctionne pas par défaut en Rust. Le compilateur ne sait pas comment déterminer si deux structures sont égales — vous devez le lui indiquer en implémentant le trait PartialEq.
Comme Debug et Copy, vous pouvez dériver PartialEq automatiquement :
#[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
Lorsqu'il est dérivé, PartialEq compare chaque champ de la structure. Deux instances sont égales seulement si tous leurs champs correspondants sont identiques.
Vous rencontrerez également Eq, qui est un trait marqueur indiquant l'égalité totale—ce qui signifie que chaque valeur est égale à elle-même. La plupart des types satisfont à cela, mais pas les nombres à virgule flottante (car NaN != NaN). Pour les structures avec des champs entiers, vous pouvez dériver les deux en toute sécurité :
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
Eq n'a pas de méthodes propres — il signale simplement que le type possède une égalité réflexive. Certaines fonctionnalités de la bibliothèque standard nécessitent Eq en plus de PartialEq, il est donc courant de dériver les deux ensemble pour les types qui y sont éligibles.
Défi
FacileConstruisons un système de correspondance de couleurs qui démontre comment les traits PartialEq et Eq permettent la comparaison entre des instances de structures !
Vous allez créer deux fichiers pour organiser votre logique de comparaison de couleurs :
color.rs: Définissez une structure publiqueColoravec trois champs publics :red,green, etblue(tous de typeu8). Dérivez à la foisPartialEqetEqafin que deux couleurs puissent être comparées à l'aide de==. Lorsqu'ils sont dérivés, Rust considérera que deux couleurs sont égales uniquement si les trois composants RVB correspondent exactement.main.rs: Importez votre module de couleur et créez deux instances deColoren utilisant les entrées fournies. Comparez-les en utilisant==et affichez si elles correspondent ou non.
Votre sortie doit indiquer si les deux couleurs sont identiques :
Color 1: rgb({r1}, {g1}, {b1})
Color 2: rgb({r2}, {g2}, {b2})
Colors match: {true/false}Par exemple, avec les entrées 255, 128, 0, 255, 128, 0 :
Color 1: rgb(255, 128, 0)
Color 2: rgb(255, 128, 0)
Colors match: trueEt avec les entrées 100, 100, 100, 200, 200, 200 :
Color 1: rgb(100, 100, 100)
Color 2: rgb(200, 200, 200)
Colors match: falseVous recevrez six entrées : les valeurs RVB pour la première couleur (trois valeurs), suivies des valeurs RVB pour la seconde couleur (trois valeurs). Analysez chacune d'elles comme un u8.
Aide-mémoire
Pour comparer des structures personnalisées à l'aide de ==, implémentez le trait PartialEq en le dérivant :
#[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
Lorsqu'il est dérivé, PartialEq compare tous les champs — deux instances sont égales uniquement si tous les champs correspondants correspondent.
Le trait Eq est un trait marqueur indiquant une égalité totale (chaque valeur est égale à elle-même). La plupart des types satisfont à cela, à l'exception des nombres à virgule flottante (car NaN != NaN). Pour les structures avec des champs de type entier, dérivez les deux traits ensemble :
#[derive(PartialEq, Eq)]
struct Coordinate {
x: i32,
y: i32,
}
Eq n'a pas de méthodes — il signale une égalité réflexive. Certaines fonctionnalités de la bibliothèque standard nécessitent Eq en plus de PartialEq.
Essayez vous-même
mod color;
use color::Color;
fn main() {
// Lire les six valeurs 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: Créer deux instances de Color en utilisant les valeurs analysées
// TODO: Afficher Color 1 au format : Color 1: rgb(r, g, b)
// TODO: Afficher Color 2 au format : Color 2: rgb(r, g, b)
// TODO: Comparer les deux couleurs en utilisant == et afficher : Colors match: {true/false}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Object Oriented Programming
1Méthodes et comportement
Introduction aux blocs d'implémentationLe paramètre SelfMéthodes mutablesFonctions associéesBlocs d'implémentation multiplesChaînage de méthodesRécapitulatif - Actions sur le rectangle4Projet : Animal virtuel
Définir l'animalNourrir l'animal7Traits standards
Le trait DebugLe trait DisplayClone et CopyLes traits d'égalitéRécapitulatif - Point affichable10Projet : Système de documents
Le trait DrawComposant texte2Encapsulation et modules
Bases des modulesLe mot-clé publicChamps privésGettersSettersRécapitulatif - Casier sécurisé5Généricité
Structures génériquesMéthodes génériquesPlusieurs types génériquesFonctions génériquesRécapitulatif - Point de coordonnées8Les Traits comme contraintes
Syntaxe des contraintes de traitContraintes multiplesLa clause whereRetourner des types avec des traitsRécapitulatif - Afficheur générique11Design Patterns en Rust
Le pattern NewtypeCompositionLe trait DropFrom et IntoRécapitulatif - Mock de Smart Pointer3Enums avancées
Enums avec donnéesMéthodes sur les EnumsMatching des variantes de donnéesL'Enum Option revisitéeRécapitulatif - Enum Shape6Définition des Traits
Qu'est-ce qu'un Trait ?Implémenter des TraitsImplémentations par défautRedéfinir les comportements par défautTraits avec paramètresRécapitulatif - Lecteur multimédia