Contraintes multiples
Fait partie de la section Programmation Orientée Objet du Journey Rust de Coddy. Leçon 41 sur 61.
Parfois, une seule contrainte de trait ne suffit pas. Vous pouvez avoir besoin d’un type générique qui peut à la fois être affiché et fournir un résumé. Rust vous permet d’exiger plusieurs traits à l’aide de la syntaxe +.
Voici comment spécifier qu’un type doit implémenter deux traits :
use std::fmt::Display;
trait Summary {
fn summarize(&self) -> String;
}
fn announce<T: Display + Summary>(item: T) {
println!("Breaking news: {}", item);
println!("Summary: {}", item.summarize());
}
La contrainte T: Display + Summary signifie que « T doit implémenter à la fois Display et Summary ». À l’intérieur de la fonction, tu peux utiliser les fonctionnalités des deux traits : l’affichage avec {} (fourni par Display) et l’appel de summarize() (fourni par Summary).
Vous pouvez enchaîner autant de traits que nécessaire :
fn process<T: Display + Summary + Clone>(item: T) {
// Peut imprimer, résumer ET cloner
}
Ce modèle est essentiel lorsque votre fonction dépend de plusieurs comportements. Plutôt que d’accepter n’importe quel type et d’espérer que cela fonctionne, vous déclarez explicitement les capacités précises requises, et le compilateur les vérifie à la compilation.
Défi
FacileConstruisons un système d’inspection de produits qui exige que les articles possèdent plusieurs capacités ! Vous allez créer une fonction générique qui n’accepte que les types implémentant à la fois un trait personnalisé et un trait standard, afin de montrer comment la syntaxe + combine plusieurs contraintes.
Vous organiserez votre code sur deux fichiers :
product.rs: Définissez un trait publicInspectableavec une méthode appeléeinspectqui prend&selfet renvoie uneStringcontenant les détails de l’inspection. Créez ensuite une structure publiqueGadgetavec les champs publicsname(String) etserial(u32). Votre Gadget doit implémenter à la foisInspectable(en renvoyantInspecting: {name}) etstd::fmt::Display(avec le format{name} (SN: {serial})). Enfin, créez une fonction générique publique appeléefull_reportqui accepte tout typeTimplémentant à la foisDisplayetInspectable. Cette fonction doit afficher deux lignes : d’abord l’article à l’aide du formateur{}, puis le résultat de l’appel àinspect().main.rs: Importez votre module product et créez une instance deGadgetà l’aide des entrées fournies. Appelezfull_reportavec votre gadget pour montrer qu’il satisfait aux deux exigences de trait.
L’intérêt des contraintes multiples est que votre fonction full_report peut utiliser les capacités des deux traits, en affichant l’article de manière agréable ET en obtenant les détails de l’inspection, le tout garanti à la compilation.
Votre sortie doit afficher à la fois le format d’affichage et le résultat de l’inspection :
{name} (SN: {serial})
Inspecting: {name}Par exemple, avec les entrées Smartwatch et 98765 :
Smartwatch (SN: 98765)
Inspecting: SmartwatchVous recevrez deux entrées : le nom du gadget et le numéro de série (à analyser en tant que u32).
Essayez vous-même
mod product;
use product::{Gadget, full_report};
fn main() {
// Lire les entrées
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
let mut serial_input = String::new();
std::io::stdin().read_line(&mut serial_input).expect("Failed to read line");
let serial: u32 = serial_input.trim().parse().expect("Failed to parse serial");
// TODO: Créer une instance de Gadget avec le name et le serial
// TODO: Appeler full_report avec votre gadget
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
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édiaEntraînez-vous par vous-même : Compilateur Rust en ligne