Menu
Coddy logo textTech

Fonctions génériques

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

Les génériques ne se limitent pas aux structures. Vous pouvez également écrire des fonctions autonomes qui fonctionnent avec n’importe quel type. Cela est utile lorsque vous avez besoin d’une fonction utilitaire qui n’appartient pas à une structure spécifique, mais qui doit tout de même rester flexible.

La syntaxe reprend ce que vous avez vu avec les structures. Déclarez le paramètre générique entre chevrons après le nom de la fonction, puis utilisez-le dans les paramètres et le type de retour :

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

Cette fonction identity prend une valeur de n’importe quel type et la renvoie inchangée. <T> déclare le générique, value: T l’accepte comme paramètre et -> T spécifie le type de retour. Lorsque vous appelez la fonction, Rust déduit le type concret :

let num = identity(42);        // T est i32
let text = identity("hello");  // T est &str

Vous pouvez également utiliser plusieurs paramètres génériques dans les fonctions, tout comme avec les structs :

fn make_pair<T, U>(first: T, second: U) -> (T, U) {
    (first, second)
}

let pair = make_pair(10, "ten");  // retourne (i32, &str)

Les fonctions génériques vous permettent d’écrire une logique réutilisable une seule fois et de l’appliquer à de nombreux types, ce qui réduit la duplication du code tout en maintenant la sécurité des types.

challenge icon

Défi

Facile

Construisons un module utilitaire avec des fonctions génériques capables de fonctionner avec n’importe quel type ! Tu vas créer des fonctions autonomes qui montrent comment les génériques rendent ton code flexible et réutilisable, sans le lier à une structure spécifique.

Tu vas organiser ton code sur deux fichiers :

  • utils.rs : Crée une collection de fonctions utilitaires génériques publiques :
    • wrap_in_pair<T> : prend une valeur unique et renvoie un tuple contenant deux fois cette valeur : (value, value). Cela nécessite que le type implémente Clone, utilise donc <T: Clone>
    • swap<T, U> : prend deux valeurs de types potentiellement différents et les renvoie dans l’ordre inverse sous forme de tuple (U, T)
  • main.rs : Importe ton module utilitaire et montre ces fonctions génériques en fonctionnement avec différents types. Montre comment les mêmes définitions de fonctions traitent facilement les entiers, les nombres flottants et les chaînes.

Dans ton fichier principal, montre tes fonctions utilitaires en :

  1. Utilisant wrap_in_pair avec un entier (première entrée, analysée comme i32) et en affichant les deux éléments
  2. Utilisant wrap_in_pair avec une chaîne (deuxième entrée) et en affichant les deux éléments
  3. Utilisant swap avec un entier (troisième entrée, analysée comme i32) et une chaîne (quatrième entrée), puis en affichant le résultat de l’échange

Ta sortie doit respecter ce format :

Pair of ints: ({value}, {value})
Pair of strings: ({value}, {value})
Swapped: ({string}, {int})

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

Pair of ints: (5, 5)
Pair of strings: (hello, hello)
Swapped: (world, 42)

Remarque que wrap_in_pair fonctionne de manière identique pour les entiers et les chaînes, et que swap traite deux types complètement différents : c’est toute la flexibilité des fonctions génériques !

Tu recevras quatre entrées : un entier, une chaîne, un autre entier et une autre chaîne.

Essayez vous-même

mod utils;

use std::io;

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

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

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

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

    // TODO: Utiliser wrap_in_pair avec num1 et afficher le résultat
    // Format: Pair of ints: ({value}, {value})

    // TODO: Utiliser wrap_in_pair avec str1 et afficher le résultat
    // Format: Pair of strings: ({value}, {value})

    // TODO: Utiliser swap avec num2 et str2, puis afficher le résultat échangé
    // Format : Échangé : ({string}, {int})
}
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