Menu
CoddyTech

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. Tu peux aussi écrire des fonctions autonomes qui fonctionnent avec n’importe quel type. C’est utile lorsque tu as besoin d’une fonction utilitaire qui n’appartient pas à une structure spécifique, mais qui doit rester flexible.

La syntaxe reprend celle que tu as vue avec les structures. Déclare le paramètre générique entre chevrons après le nom de la fonction, puis utilise-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 sans la modifier. <T> déclare le type générique, value: T l’accepte en tant que paramètre et -> T indique le type de retour. Lorsque tu appelles la fonction, Rust déduit le type concret :

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

Tu peux aussi 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");  // renvoie (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 préservant la sécurité des types.

challenge icon

Défi

Facile

Construisons un module utilitaire contenant des fonctions génériques qui peuvent 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 rattacher à une structure spécifique.

Tu vas répartir ton code dans deux fichiers :

  • utils.rs : crée un ensemble de fonctions utilitaires génériques publiques :
    • wrap_in_pair<T> : prend une seule valeur et renvoie un tuple contenant deux fois cette valeur : (value, value). Le type doit implémenter 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 action avec différents types. Montre comment les mêmes définitions de fonctions traitent sans difficulté des entiers, des nombres à virgule flottante et des chaînes de caractères.

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 de caractères (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 de caractères (quatrième entrée), puis en affichant le résultat après permutation

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 la même façon avec les entiers et les chaînes de caractères, et que swap gère deux types complètement différents : voilà toute la flexibilité des fonctions génériques !

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

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 après échange
    // Format : Swapped: ({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