Redéfinir les comportements par défaut
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 32 sur 61.
Les implémentations par défaut sont pratiques, mais parfois un type a besoin d'un comportement qui diffère de la norme. Lorsque cela se produit, vous pouvez surcharger le comportement par défaut en fournissant votre propre implémentation dans le bloc impl.
Définissez simplement la méthode avec la même signature, mais incluez votre logique personnalisée :
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
Même si Greet fournit une méthode greet par défaut, Robot la remplace entièrement par sa propre version. Lorsque vous appelez greet() sur un Robot, Rust utilise l'implémentation personnalisée :
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unité 42 en ligne.
Cela vous offre de la flexibilité : les types qui se contentent du comportement par défaut n'ont rien à écrire, tandis que les types nécessitant un comportement spécialisé peuvent redéfinir uniquement les méthodes qui les intéressent. Le trait garantit toujours que chaque type implémentant dispose de la méthode.
Défi
FacileConstruisons un système de notification où différents types d'alertes peuvent personnaliser leurs messages ! Vous allez créer un trait avec une implémentation par défaut, puis faire en sorte qu'un type utilise cette valeur par défaut tandis qu'un autre la surcharge avec un comportement personnalisé.
Vous organiserez votre code sur trois fichiers :
notifiable.rs: Définissez un trait publicNotifiableavec une méthodenotify(&self) -> Stringqui possède une implémentation par défaut retournant"Alert: Something happened!".alerts.rs: Créez deux structures publiques qui implémentent votre trait différemment :GenericAlert— une structure unité (unit struct) qui utilise la notification par défaut (bloc impl vide).UrgentAlert— une structure avec un champ publicmessage(String) qui surcharge le comportement par défaut pour retourner"URGENT: {message}"où{message}est son message stocké.
main.rs: Rassemblez vos modules et démontrez les deux comportements. Créez unGenericAlertet unUrgentAlerten utilisant l'entrée fournie, puis affichez leurs notifications.
L'idée clé ici est que GenericAlert bénéficie gratuitement du comportement par défaut, tandis que UrgentAlert fournit sa propre version spécialisée en définissant la méthode dans son bloc impl.
Votre sortie doit suivre ce format :
Alert: Something happened!
URGENT: {message}Par exemple, avec l'entrée Server is down! :
Alert: Something happened!
URGENT: Server is down!Vous recevrez une entrée : le message pour l'alerte urgente.
Aide-mémoire
Vous pouvez surcharger les implémentations de trait par défaut en fournissant votre propre implémentation dans le bloc impl :
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unité 42 en ligne.
Les types qui n'ont pas besoin d'un comportement personnalisé peuvent utiliser un bloc impl vide pour accepter l'implémentation par défaut, tandis que les types nécessitant un comportement spécialisé peuvent surcharger des méthodes spécifiques en les définissant avec la même signature.
Essayez vous-même
mod notifiable;
mod alerts;
use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;
fn main() {
// Lire l'entrée pour le message d'alerte urgente
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Créer une instance de GenericAlert
// TODO: Créer une instance de UrgentAlert avec le message d'entrée
// TODO: Imprimer la notification de GenericAlert
// TODO: Imprimer la notification de UrgentAlert
}
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