Menu
Coddy logo textTech

Enums avec données

Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 14 sur 61.

Les enums de base en Rust vous permettent de définir un type avec un ensemble fixe de variantes — comme Direction::North ou Status::Active. Mais les enums Rust sont bien plus puissantes que cela. Chaque variante peut transporter ses propres données, ce qui rend les enums incroyablement flexibles pour modéliser des scénarios du monde réel.

Considérez un système de messagerie où différents types de messages transportent des informations différentes. Un message texte a un contenu, une commande de déplacement a des coordonnées, et un signal de sortie n'a rien du tout. En Rust, vous pouvez représenter tout cela avec un seul enum :

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

Chaque variante a une forme différente. Quit ne contient aucune donnée — c'est juste un signal.

Move utilise une syntaxe de type struct avec des champs nommés. Write contient une seule String en utilisant la syntaxe de tuple. ChangeColor contient trois valeurs représentant les composants RGB.

La création d'instances de ces variantes ressemble à ceci :

let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);

La beauté de cette approche est que m1, m2, m3 et m4 sont tous du même type : Message. Vous pouvez les stocker dans la même collection, les passer à la même fonction ou retourner n'importe quelle variante à partir d'une seule fonction. L'énumération unifie différentes formes de données sous un seul type tout en préservant les informations spécifiques dont chaque variante a besoin.

challenge icon

Défi

Facile

Construisons un système de notification qui utilise des enums avec des données pour représenter différents types d'alertes. Chaque type de notification transporte des informations différentes — certaines ont des messages, d'autres ont des valeurs numériques, et certaines sont de simples signaux.

Vous allez créer deux fichiers pour organiser votre code :

  • notification.rs : Définissez un enum public Notification avec trois variantes :
    • Alert — contient un seul message String (syntaxe de tuple)
    • Reminder — contient des champs nommés : title (String) et minutes (u32)
    • Dismiss — ne contient aucune donnée, juste un signal
  • main.rs : Importez votre module de notification et créez une instance de chaque variante. Ensuite, affichez les informations de chaque notification pour démontrer que les trois variantes sont du même type mais transportent des données différentes.

Lors de l'affichage, utilisez le formatage de débogage ({:?}) pour afficher chaque notification. Vous devrez dériver le trait Debug sur votre enum pour qu'il puisse être affiché de cette manière.

Votre sortie devrait afficher les trois notifications, chacune sur sa propre ligne :

Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
Dismiss

Par exemple, avec un message d'alerte de "Server down", un rappel avec le titre "Meeting" et 30 minutes, la sortie serait :

Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
Dismiss

Vous recevrez trois entrées : le message d'alerte, le titre du rappel et les minutes du rappel.

Aide-mémoire

Les variantes d'énumération en Rust peuvent transporter différents types de données, ce qui les rend puissantes pour modéliser divers scénarios sous un seul type.

Définir des énumérations avec des données

Chaque variante peut avoir sa propre structure de données :

enum Message {
    Quit,                          // Aucune donnée
    Move { x: i32, y: i32 },      // Champs nommés (semblable à une structure)
    Write(String),                 // Valeur unique (syntaxe de tuple)
    ChangeColor(u8, u8, u8),      // Valeurs multiples (syntaxe de tuple)
}

Créer des instances d'énumération

let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);

Toutes les instances sont du même type (Message) bien qu'elles transportent des données différentes, ce qui permet de les stocker dans des collections, de les passer à des fonctions ou de les retourner depuis des fonctions de manière uniforme.

Trait Debug

Pour afficher des énumérations en utilisant le formatage {:?}, dérivez le trait Debug :

#[derive(Debug)]
enum Message {
    // variantes...
}

Essayez vous-même

mod notification;

use notification::Notification;

fn main() {
    // Lire les entrées
    let mut alert_message = String::new();
    std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
    let alert_message = alert_message.trim().to_string();

    let mut reminder_title = String::new();
    std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
    let reminder_title = reminder_title.trim().to_string();

    let mut minutes_input = String::new();
    std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
    let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");

    // TODO: Créer une notification Alert en utilisant alert_message

    // TODO: Créer une notification Reminder en utilisant reminder_title et reminder_minutes

    // TODO: Créer une notification Dismiss

    // TODO: Afficher chaque notification en utilisant le formatage de débogage {:?}
    // Chaque notification doit être affichée sur sa propre ligne
}
quiz iconTestez-vous

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