Menu
Coddy logo textTech

Vecteurs de traits

Fait partie de la section Programmation Orientée Objet du Journey Rust de Coddy. Leçon 46 sur 61.

Vous avez vu comment Box<dyn Trait> permet à une seule variable de contenir différents types. La véritable puissance apparaît lorsque vous combinez cela avec des collections : stocker plusieurs types différents dans un seul vecteur.

Un vecteur classique exige que tous les éléments soient du même type. Vous ne pouvez pas avoir un Vec<Dog> qui contienne également des chats. Mais avec les objets de trait, vous pouvez créer un vecteur qui contient n'importe quoi implémentant un trait commun :

trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;
struct Bird;

impl Speak for Dog {
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Speak for Cat {
    fn speak(&self) -> String { String::from("Meow!") }
}

impl Speak for Bird {
    fn speak(&self) -> String { String::from("Tweet!") }
}

fn main() {
    let animals: Vec<Box<dyn Speak>> = vec![
        Box::new(Dog),
        Box::new(Cat),
        Box::new(Bird),
    ];
}

Le type Vec<Box<dyn Speak>> signifie « un vecteur d’objets de trait encapsulés ». Chaque élément est un Box pointant vers quelque chose qui implémente Speak : les types réels peuvent être différents. Tu encapsules chaque valeur avec Box::new() lorsque tu l’ajoutes au vecteur.

Ce modèle est essentiel pour créer des systèmes flexibles dans lesquels vous devez gérer des collections d’objets apparentés, mais différents, comme des composants d’interface utilisateur, des entités de jeu ou des systèmes de plugins.

challenge icon

Défi

Facile

Construisons un système de notifications capable de gérer différents types d’alertes ! Vous allez créer une collection qui stocke différents types de notifications, des e-mails, des messages SMS et des notifications push, le tout dans un seul vecteur utilisant des objets de trait.

Vous allez organiser votre code sur deux fichiers :

  • notifications.rs : définissez un trait public Notify avec une méthode send qui prend &self et renvoie une String décrivant la notification envoyée. Créez ensuite trois structures publiques :
    • Email : avec un champ public recipient (String). Son send doit renvoyer Email to: {recipient}
    • Sms : avec un champ public phone (String). Son send doit renvoyer SMS to: {phone}
    • Push : avec un champ public device (String). Son send doit renvoyer Push to: {device}
  • main.rs : importez votre module de notifications et créez un vecteur de type Vec<Box<dyn Notify>> qui contient les trois types de notifications. Utilisez les entrées fournies pour créer une notification de chaque type, ajoutez-les à votre vecteur dans l’ordre (Email, Sms, Push), puis affichez le résultat de l’appel à send() sur le premier élément du vecteur.

Le concept clé ici est que, bien que Email, Sms et Push soient des structures complètement différentes, elles peuvent toutes coexister dans le même vecteur, car elles partagent le trait Notify. Chaque élément est encapsulé avec Box::new() pour créer l’objet de trait.

Votre sortie doit afficher la première notification :

Email to: {recipient}

Par exemple, avec les entrées alice@example.com, 555-1234 et iPhone-12 :

Email to: alice@example.com

Vous recevrez trois entrées : le destinataire de l’e-mail, le numéro de téléphone et le nom de l’appareil.

Essayez vous-même

mod notifications;

use notifications::{Notify, Email, Sms, Push};

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

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

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

    // TODO: Créer un Vec<Box<dyn Notify>> pour contenir différents types de notification
    // TODO: Créer des instances Email, Sms et Push en utilisant les entrées
    // TODO: Les ajouter au vecteur dans l'ordre (Email, Sms, Push) en utilisant Box::new()
    // TODO: Afficher le résultat de l'appel à send() sur le premier élément
}
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 Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur Rust en ligne