Contraintes multiples
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy. Leçon 41 sur 61.
Parfois, une seule borne de trait ne suffit pas. Vous pourriez 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 en utilisant 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, vous pouvez utiliser les fonctionnalités des deux traits — l'affichage avec {} (provenant de Display) et l'appel à summarize() (provenant de Summary).
Vous pouvez enchaîner autant de traits que nécessaire :
fn process<T: Display + Summary + Clone>(item: T) {
// Peut afficher, résumer ET cloner
}
Ce pattern est essentiel lorsque votre fonction repose sur plusieurs comportements. Plutôt que d'accepter n'importe quel type en espérant que cela fonctionne, vous déclarez explicitement les capacités exactes requises — et le compilateur l'impose au moment de 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, démontrant ainsi comment la syntaxe + combine plusieurs bornes (bounds).
Vous organiserez votre code sur deux fichiers :
product.rs: Définissez un trait publicInspectableavec une méthode appeléeinspectqui prend&selfet retourne unStringcontenant les détails de l'inspection. Créez ensuite une structure publiqueGadgetavec des champs publicsname(String) etserial(u32). Votre Gadget doit implémenter à la foisInspectable(retournant"Inspecting: {}"avec le nom) etstd::fmt::Display(formaté comme"{} (SN: {})"). Enfin, créez une fonction générique publique appeléefull_reportqui accepte n'importe quel typeTimplémentant à la foisDisplayetInspectable. Cette fonction doit imprimer deux lignes : d'abord l'article en utilisant le formateur{}, puis le résultat de l'appel àinspect().main.rs: Importez votre module product et créez une instance deGadgeten utilisant les entrées fournies. Appelezfull_reportavec votre gadget pour montrer qu'il satisfait aux exigences des deux traits.
La puissance des bornes multiples est que votre fonction full_report peut utiliser les capacités des deux traits — afficher l'article proprement ET obtenir les détails de l'inspection — le tout garanti au moment de la compilation.
Votre sortie devrait 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 comme un 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 nom et le numéro de série
// 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 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édiaEntraînez-vous par vous-même : Compilateur Rust en ligne