Menu
Coddy logo textTech

Structures génériques

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

Jusqu’à présent, chaque struct que tu as créée avait des champs avec des types spécifiques et concrets. Un Pet a un nom de type String, un Rectangle a des dimensions de type f64. Mais que faire si tu veux créer une struct capable de contenir any type de données ?

C’est là qu’interviennent les génériques. Les génériques vous permettent d’écrire du code flexible et réutilisable qui fonctionne avec plusieurs types. Au lieu de coder en dur un type spécifique, vous utilisez un espace réservé, généralement T, qui est remplacé par un type concret lorsque vous utilisez la structure.

Voici une structure enveloppe simple qui peut contenir n’importe quel type :

struct Wrapper<T> {
    value: T,
}

Le <T> après le nom de la structure déclare un paramètre de type générique. Dans la structure, T sert de substitut au type que tu utiliseras réellement. Lorsque tu crées une instance, Rust déduit le type concret :

let int_wrapper = Wrapper { value: 42 };        // T est i32
let float_wrapper = Wrapper { value: 3.14 };    // T est f64
let text_wrapper = Wrapper { value: "hello" };  // T est &str

Chacun de ces éléments est un type concret différent, Wrapper<i32>, Wrapper<f64> et Wrapper<&str>, mais ils partagent tous la même définition de struct. Cela évite d’avoir à écrire des structs IntWrapper, FloatWrapper et StringWrapper distincts qui font essentiellement la même chose.

La lettre T n’est qu’une convention (abréviation de « type »). Tu pourrais utiliser n’importe quel identifiant valide, mais T est la convention standard en Rust et dans la plupart des autres langages prenant en charge les génériques.

challenge icon

Défi

Facile

Construisons un conteneur générique capable de contenir n’importe quel type de valeur ! Vous allez créer une structure Container qui montre comment les génériques rendent votre code flexible et réutilisable.

Vous organiserez votre code sur deux fichiers :

  • container.rs : définissez une structure générique publique appelée Container<T> avec un seul champ public item de type T. Ce conteneur doit pouvoir contenir n’importe quel type : des entiers, des nombres à virgule flottante, des chaînes de caractères ou quoi que ce soit d’autre.
  • main.rs : importez votre module de conteneur et démontrez sa flexibilité en créant des conteneurs qui contiennent différents types de données. Vous créerez trois conteneurs et afficherez le contenu de chacun.

Dans votre fichier principal, créez les conteneurs suivants :

  1. Un conteneur contenant une valeur entière (la première entrée, analysée comme un i32)
  2. Un conteneur contenant une valeur à virgule flottante (la deuxième entrée, analysée comme un f64)
  3. Un conteneur contenant une chaîne de caractères (la troisième entrée, conservée en tant que String)

Votre sortie doit afficher le contenu de chaque conteneur dans ce format :

Integer container: {value}
Float container: {value}
String container: {value}

Par exemple, avec les entrées 42, 3.14 et hello :

Integer container: 42
Float container: 3.14
String container: hello

Remarquez comment la même définition de Container<T> fonctionne pour les trois types différents : c’est là toute la puissance des génériques !

Vous recevrez trois entrées : une valeur entière, une valeur à virgule flottante et une chaîne de caractères.

Essayez vous-même

mod container;

use container::Container;

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

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let float_value: f64 = input2.trim().parse().expect("Failed to parse float");

    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: Create three containers using Container<T>
    // 1. An integer container holding int_value
    // 2. A float container holding float_value
    // 3. A string container holding string_value

    // TODO: Afficher le contenu de chaque conteneur dans le format requis
    // Integer container: {value}
    // Float container: {value}
    // String container: {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 Programmation Orientée Objet

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