Implémenter des Traits
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 30 sur 61.
Maintenant que vous savez comment définir un trait, voyons comment faire en sorte qu'une struct remplisse ce contrat. L'implémentation d'un trait relie l'exigence abstraite à un comportement concret.
La syntaxe utilise impl TraitName for StructName :
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Le bloc impl Speak for Dog indique à Rust que Dog implémente le trait Speak. À l'intérieur, vous fournissez le corps de la méthode proprement dit — c'est ici que vous définissez comment un chien parle.
La puissance des traits devient évidente lorsque plusieurs types implémentent le même :
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
Dog et Cat partagent désormais tous deux la capacité Speak, mais chacun fournit sa propre implémentation unique. Vous pouvez appeler .speak() sur l'un ou l'autre type :
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex dit : Woof !
println!("{}", cat.speak()); // Whiskers dit : Meow !
C'est le fondement du polymorphisme en Rust — différents types, même interface, comportements uniques.
Défi
FacileDonnons vie aux traits en les implémentant pour différents types ! Vous allez créer un trait Describable et l'implémenter pour deux structures différentes, chacune fournissant sa propre description unique.
Vous organiserez votre code sur trois fichiers :
describable.rs: Définissez un trait publicDescribableavec une méthodedescribe(&self) -> String.items.rs: Créez deux structures publiques qui implémentent votre trait :Bookavec un champ publictitle(String)Movieavec un champ publicname(String)
Describableavec son propre format de description unique.main.rs: Rassemblez vos modules, créez des instances des deux structures et appelez leurs méthodesdescribepour montrer comment le même trait produit des sorties différentes pour différents types.
Votre Book doit se décrire comme Book: {title} et votre Movie doit se décrire comme Film: {name}. Remarquez comment chaque type remplit le même contrat mais avec son propre comportement !
Dans votre fichier principal, créez un livre et un film en utilisant les deux entrées fournies, puis affichez leurs descriptions sur des lignes séparées.
Votre sortie doit suivre ce format :
Book: {title}
Film: {name}Par exemple, avec les entrées 1984 et Inception :
Book: 1984
Film: InceptionVous recevrez deux entrées : un titre de livre et un nom de film.
Aide-mémoire
Pour implémenter un trait pour une structure, utilisez la syntaxe impl TraitName for StructName :
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Plusieurs types peuvent implémenter le même trait avec des comportements différents :
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex says: Woof!
println!("{}", cat.speak()); // Whiskers says: Meow!
Cela permet le polymorphisme en Rust — différents types partageant la même interface avec des implémentations uniques.
Essayez vous-même
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// Lire les entrées
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: Créer une instance de Book avec le titre
// TODO: Créer une instance de Movie avec le nom
// TODO: Afficher la description du livre
// TODO: Afficher la description du film
}
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