Passer au contenu principal
eLearner.app
Module 5 · Leçon 1 sur 29/14 dans le cours~12 min
Leçons du module (1/2)

Génériques et fonctions

Les generics (types génériques) permettent d'écrire du code flexible et réutilisable, en évitant la duplication de logique pour différents types de données. Au lieu de définir plusieurs fonctions ou structures pour des types différents (tels que i32, f64 ou String), nous pouvons utiliser un paramètre de type générique, conventionnellement désigné par la lettre T.

Le compilateur Rust gère les generics à l'aide d'un processus appelé monomorphisation : lors de la compilation, le compilateur génère une copie du code générique pour chaque type concret avec lequel il est réellement utilisé. De cette façon, il n'y a aucune surcharge de performance à l'exécution.


Fonctions Génériques

Pour définir une fonction générique, nous insérons le paramètre de type <T> juste après le nom de la fonction et avant la liste des paramètres :

Code
fn print_value<T: std::fmt::Debug>(value: T) {
    println!("Valore: {:?}", value);
}

Dans les fonctions génériques, nous pouvons utiliser le type générique T à la fois pour les types des arguments et pour le type de retour :

Code
fn identity<T>(value: T) -> T {
    value
}

Structures Génériques

Nous pouvons également utiliser des paramètres de type générique à l'intérieur des structures de données (struct) pour définir des champs flexibles :

Code
struct KeyValuePair<K, V> {
    key: K,
    value: V,
}

fn main() {
    let pair = KeyValuePair {
        key: String::from("eta"),
        value: 30,
    };
}

Dans le bloc impl pour une struct générique, nous devons déclarer le paramètre de type <T> juste après le mot-clé impl pour indiquer que nous implémentons des méthodes sur une structure générique :

Code
struct Container<T> {
    value: T,
}

impl<T> Container<T> {
    fn new(value: T) -> Self {
        Container { value }
    }

    fn value(&self) -> &T {
        &self.value
    }
}

À toi de jouer

Exercice 1 : La structure Point

Exercice#rust.m5.l1.e1
Tentatives : 0Chargement…

Définissez une structure générique nommée Point<T> avec deux champs : x de type T et y de type T. Dans le main, instanciez une variable point contenant un Point avec des valeurs x égales à 5 et y égales à 10 (entiers), puis affichez à l'écran la valeur de point.x.

Chargement de l'éditeur…
Afficher l'indice

Déclarez la struct en utilisant `struct Point<T> { x: T, y: T }`. Instanciez-la dans le main et utilisez `point.x` pour l'afficher.

Solution disponible après 3 tentatives

Exercice 2 : Inversion d'un Tuple avec swap

Exercice#rust.m5.l1.e2
Tentatives : 0Chargement…

Écrivez une fonction générique nommée swap<T> qui accepte en entrée un tuple de deux éléments (T, T) et renvoie un nouveau tuple (T, T) avec les éléments inversés de position. Dans le main, appelez la fonction avec le tuple (1, 2) et affichez le résultat.

Chargement de l'éditeur…
Afficher l'indice

La signature de la fonction doit être `fn swap<T>(pair: (T, T)) -> (T, T)`. Renvoyez le tuple inversé avec `(pair.1, pair.0)`.

Solution disponible après 3 tentatives

Exercice 3 : La structure Container

Exercice#rust.m5.l1.e3
Tentatives : 0Chargement…

Définissez une struct générique Container<T> contenant un champ value de type T. Implémentez un bloc impl générique pour définir une méthode new qui accepte une valeur de type T et renvoie une instance de Container<T>.

Chargement de l'éditeur…
Afficher l'indice

Utilisez `impl<T> Container<T>`pour implémenter la méthode associée`fn new(value: T) -> Self { Container { value } }`.

Solution disponible après 3 tentatives