Menu
Coddy logo textTech

Méthodes génériques

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

Une structure générique peut contenir n'importe quel type, mais elle n'est pas très utile sans méthodes pour interagir avec ses données. Pour définir des méthodes pour une structure générique, vous avez besoin d'une syntaxe spéciale dans le bloc impl.

La clé est de déclarer le paramètre générique sur le impl lui-même :

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

Remarquez le impl<T> avant Wrapper<T>. Cela indique à Rust que T est un paramètre de type générique pour l'ensemble du bloc d'implémentation. Sans cette déclaration, Rust chercherait un type concret nommé T et ne parviendrait pas à le trouver.

La méthode get renvoie &T—une référence vers le type contenu par le wrapper. Cela fonctionne que T soit un entier, une chaîne de caractères ou tout autre type :

let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };

println!("{}", num_wrapper.get());  // 100
println!("{}", text_wrapper.get()); // Rust

La même définition de méthode fonctionne pour les deux, car le générique T s'adapte à chaque type concret au moment de la compilation.

challenge icon

Défi

Facile

Étendez votre conteneur générique avec des méthodes ! Vous allez construire une structure Box (à ne pas confondre avec la structure Box standard de Rust) qui peut contenir n'importe quel type et fournit des méthodes pour interagir avec son contenu.

Vous organiserez votre code sur deux fichiers :

  • mybox.rs : Définissez une structure générique publique appelée MyBox<T> avec un champ privé contents de type T. Implémentez des méthodes pour cette structure :
    • Une fonction associée new qui crée une nouvelle MyBox avec la valeur donnée
    • Une méthode peek qui retourne une référence au contenu (en utilisant &self)
    • Une méthode replace qui prend une nouvelle valeur et remplace le contenu actuel (en utilisant &mut self)
  • main.rs : Importez votre module et démontrez le fonctionnement des méthodes génériques avec différents types. Vous créerez des boîtes, consulterez leur contenu et remplacerez des valeurs pour montrer les méthodes en action.

Rappelez-vous la syntaxe clé pour implémenter des méthodes sur une structure générique : vous avez besoin de impl<T> avant MyBox<T> pour indiquer à Rust que T est un paramètre générique pour tout le bloc d'implémentation.

Dans votre fichier principal, démontrez votre MyBox en :

  1. Créant une boîte avec un entier (première entrée, analysée comme i32)
  2. Consultant son contenu et en affichant la valeur
  3. Remplaçant le contenu par un nouvel entier (deuxième entrée, analysée comme i32)
  4. Consultant à nouveau pour montrer la valeur mise à jour
  5. Créant une deuxième boîte avec une chaîne de caractères (troisième entrée)
  6. Consultant le contenu de la boîte de chaîne de caractères

Votre sortie doit suivre ce format :

Integer box contains: {value}
After replace: {value}
String box contains: {value}

Par exemple, avec les entrées 10, 25, et Rust :

Integer box contains: 10
After replace: 25
String box contains: Rust

Vous recevrez trois entrées : un entier initial, un entier de remplacement et une valeur de chaîne de caractères.

Aide-mémoire

Pour définir des méthodes pour une structure générique, déclarez le paramètre générique sur le bloc impl :

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

La syntaxe impl<T> indique à Rust que T est un paramètre de type générique pour l'ensemble du bloc d'implémentation. Sans cela, Rust chercherait un type concret nommé T.

Les méthodes peuvent retourner des références vers le type générique (&T), ce qui fonctionne pour n'importe quel type concret :

let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };

println!("{}", num_wrapper.get());  // 100
println!("{}", text_wrapper.get()); // Rust

Essayez vous-même

mod mybox;

use mybox::MyBox;

fn main() {
    // Lire les entrées
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let initial_int: i32 = input1.trim().parse().expect("Invalid integer");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");

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

    // TODO: Créer un MyBox avec l'entier initial
    
    // TODO: Jeter un œil à son contenu et afficher : "Integer box contains: {value}"
    
    // TODO: Remplacer le contenu par l'entier de remplacement
    
    // TODO: Jeter un œil à nouveau et afficher : "After replace: {value}"
    
    // TODO: Créer un deuxième MyBox avec la valeur de chaîne
    
    // TODO: Jeter un œil à la boîte de chaîne et afficher : "String box contains: {value}"
}
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