Menu
CoddyTech

Plusieurs types génériques

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

Parfois, un seul paramètre générique ne suffit pas. Que faire si vous avez besoin d’une structure qui contient deux valeurs, et que ces valeurs peuvent être de types différents ? Rust vous permet d’utiliser plusieurs paramètres génériques en les séparant par des virgules.

Voici une structure Pair qui contient deux valeurs de types potentiellement différents :

struct Pair<T, U> {
    first: T,
    second: U,
}

Le <T, U> déclare deux paramètres de type indépendants. T et U peuvent être du même type ou de types complètement différents : c’est à vous de décider lors de la création d’une instance :

let both_ints = Pair { first: 10, second: 20 };       // T=i32, U=i32
let mixed = Pair { first: "hello", second: 3.14 };    // T=&str, U=f64
let reversed = Pair { first: 100, second: "world" }; // T=i32, U=&str

Lors de l’implémentation des méthodes, vous déclarez tous les paramètres génériques dans le bloc impl :

impl<T, U> Pair<T, U> {
    fn get_first(&self) -> &T {
        &self.first
    }

    fn get_second(&self) -> &U {
        &self.second
    }
}

Ce modèle est courant lorsque vous devez associer deux éléments de données liés, mais potentiellement différents, comme une paire clé-valeur, des coordonnées avec différents types numériques ou un résultat associé à des métadonnées.

challenge icon

Défi

Facile

Construisons un système de stockage clé-valeur qui démontre la puissance de plusieurs types génériques ! Vous allez créer une structure KeyValue capable d'associer deux types quelconques, idéale pour associer des libellés à des données, des identifiants à des objets ou toute autre combinaison.

Vous allez organiser votre code sur deux fichiers :

  • keyvalue.rs : définissez une structure générique publique appelée KeyValue<K, V> avec deux champs privés : key de type K et value de type V. Implémentez des méthodes pour utiliser cette structure :
    • Une fonction associée new qui crée un KeyValue à partir d'une clé et d'une valeur
    • Une méthode key qui renvoie une référence vers la clé
    • Une méthode value qui renvoie une référence vers la valeur
    • Une méthode set_value qui remplace la valeur actuelle par une nouvelle valeur
  • main.rs : importez votre module et montrez comment la même définition de structure fonctionne avec différentes combinaisons de types. Vous créerez des paires clé-valeur avec des types mixtes afin de montrer la flexibilité de plusieurs génériques.

Dans votre fichier principal, créez et utilisez les paires clé-valeur suivantes :

  1. Une paire avec une clé de type chaîne et une valeur entière (la première entrée comme clé, la deuxième entrée analysée en i32 comme valeur)
  2. Affichez la clé et la valeur
  3. Mettez à jour la valeur avec un nouvel entier (la troisième entrée analysée en i32)
  4. Affichez la valeur mise à jour
  5. Créez une deuxième paire avec une clé entière et une valeur de type chaîne (la quatrième entrée analysée en i32 comme clé, la cinquième entrée comme valeur)
  6. Affichez la clé et la valeur de cette paire

Votre sortie doit respecter ce format :

Key: {key}, Value: {value}
Updated value: {value}
Key: {key}, Value: {value}

Par exemple, avec les entrées name, 42, 100, 7 et lucky :

Key: name, Value: 42
Updated value: 100
Key: 7, Value: lucky

Remarquez que la première paire utilise KeyValue<String, i32>, tandis que la seconde utilise KeyValue<i32, String> : la même structure, mais des combinaisons de types différentes !

Vous recevrez cinq entrées : une clé de type chaîne, une valeur entière, un entier de remplacement, une clé entière et une valeur de type chaîne.

Essayez vous-même

mod keyvalue;

use keyvalue::KeyValue;

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

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

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

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

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

    // TODO: Créer une paire KeyValue<String, i32> en utilisant string_key et int_value

    // TODO: Afficher la clé et la valeur au format : "Key: {key}, Value: {value}"

    // TODO: Mettre à jour la valeur en utilisant set_value avec replacement_int

    // TODO: Print the updated value in format: "Updated value: {value}"

    // TODO: Créer une paire KeyValue<i32, String> en utilisant int_key et string_value

    // TODO: Afficher la clé et la valeur de cette paire au format : "Key: {key}, Value: {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