Matching des variantes de données
Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 16 sur 61.
Dans la leçon précédente, vous avez utilisé match à l'intérieur des méthodes d'énumération pour gérer différentes variantes. Concentrons-nous maintenant sur la manière dont match extrait réellement les données stockées à l'intérieur de ces variantes — une technique appelée la déstructuration.
Lorsque vous effectuez un filtrage par motif sur une variante d'énumération qui contient des données, vous pouvez lier ces données à des variables directement dans le motif :
enum Event {
Click { x: i32, y: i32 },
KeyPress(char),
Resize(u32, u32),
}
fn handle_event(event: Event) {
match event {
Event::Click { x, y } => {
println!("Clicked at ({}, {})", x, y);
}
Event::KeyPress(key) => {
println!("Key pressed: {}", key);
}
Event::Resize(width, height) => {
println!("Resized to {}x{}", width, height);
}
}
}
Chaque branche extrait les données différemment en fonction de la structure de la variante. Pour les variantes de type structure, vous utilisez { field_name } pour extraire les champs nommés. Pour les variantes de type tuple, vous utilisez des variables positionnelles comme (width, height).
Les noms de variables que vous choisissez deviennent disponibles à l'intérieur de cette branche du match. C'est puissant car vous vérifiez simultanément quelle variante vous avez et vous accédez à son contenu.
Le compilateur garantit que vous gérez chaque variante, et les valeurs extraites sont prêtes à être utilisées immédiatement — aucune étape supplémentaire n'est nécessaire.
Défi
FacileConstruisons un processeur de commandes qui gère différents types de commandes utilisateur. Chaque commande transporte des données différentes, et votre processeur utilisera le filtrage par motif (pattern matching) pour extraire ces données et produire les réponses appropriées.
Vous allez créer deux fichiers pour organiser votre code :
command.rs: Définissez une énumération publiqueCommandavec trois variantes :Say— contient un seul messageString(syntaxe de tuple)Move— contient des champs nommés :direction(String) etsteps(u32)Calculate— contient deux valeursi32représentant les nombres à additionner (syntaxe de tuple)
executequi utilisematchpour déstructurer chaque variante et retourner uneStringdécrivant l'action effectuée.main.rs: Importez votre module de commande, créez une instance de chaque variante de commande en utilisant les entrées fournies, et appelez la méthodeexecutesur chacune pour afficher les résultats.
Votre méthode execute doit déstructurer chaque variante pour accéder à ses données et retourner des messages dans ces formats exacts :
- Pour
Say:Saying: {message} - Pour
Move:Moving {steps} steps {direction} - Pour
Calculate:{a} + {b} = {sum}
Votre sortie doit afficher le résultat de chaque commande sur sa propre ligne :
Saying: {message}
Moving {steps} steps {direction}
{a} + {b} = {sum}Par exemple, avec un message say de "Hello world", un déplacement de 5 pas vers le "north", et un calcul de 10 et 25, la sortie serait :
Saying: Hello world
Moving 5 steps north
10 + 25 = 35Vous recevrez cinq entrées : le message say, la direction, le nombre de pas, et les deux nombres à calculer.
Aide-mémoire
Le filtrage par motif (pattern matching) avec match vous permet de déstructurer les variantes d'énumération et d'extraire leurs données directement dans le motif.
Pour les variantes de tuple, utilisez des variables positionnelles :
enum Event {
KeyPress(char),
Resize(u32, u32),
}
match event {
Event::KeyPress(key) => {
println!("Key: {}", key);
}
Event::Resize(width, height) => {
println!("{}x{}", width, height);
}
}Pour les variantes de type structure, utilisez la syntaxe des champs nommés :
enum Event {
Click { x: i32, y: i32 },
}
match event {
Event::Click { x, y } => {
println!("Clicked at ({}, {})", x, y);
}
}Les variables extraites deviennent disponibles dans leur branche de correspondance (match arm) respective, vous permettant de vérifier le type de variante et d'accéder à ses données simultanément.
Essayez vous-même
mod command;
use command::Command;
fn main() {
// Lire les entrées
let mut say_message = String::new();
std::io::stdin().read_line(&mut say_message).expect("Failed to read line");
let say_message = say_message.trim().to_string();
let mut direction = String::new();
std::io::stdin().read_line(&mut direction).expect("Failed to read line");
let direction = direction.trim().to_string();
let mut steps_input = String::new();
std::io::stdin().read_line(&mut steps_input).expect("Failed to read line");
let steps: u32 = steps_input.trim().parse().expect("Failed to parse steps");
let mut num1_input = String::new();
std::io::stdin().read_line(&mut num1_input).expect("Failed to read line");
let num1: i32 = num1_input.trim().parse().expect("Failed to parse num1");
let mut num2_input = String::new();
std::io::stdin().read_line(&mut num2_input).expect("Failed to read line");
let num2: i32 = num2_input.trim().parse().expect("Failed to parse num2");
// TODO: Créer une commande Say en utilisant say_message et l'exécuter
// TODO: Créer une commande Move en utilisant direction et steps, et l'exécuter
// TODO: Créer une commande Calculate en utilisant num1 et num2, et l'exécuter
// TODO: Afficher les résultats de chaque exécution de commande
}
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