Programmation fonctionnelle en Rust : approches et exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction à la programmation fonctionnelle en Rust

Rust est un langage multi-paradigme qui, en plus des styles impératif et orienté objet, prend activement en charge la programmation fonctionnelle. Des fonctionnalités intégrées telles que les closures, les itérateurs, un système de types puissant et l'immuabilité par défaut permettent d'écrire un code concis, sûr et expressif. Dans cet article, nous allons détailler les concepts clés de l'approche fonctionnelle en Rust et montrer comment les appliquer en pratique.



Fondements de l'approche fonctionnelle : immuabilité et fonctions pures

La programmation fonctionnelle repose sur deux piliers : l'immuabilité des données et les fonctions pures. Rust encourage l'immuabilité — par défaut, toutes les variables sont immutables. Pour modifier une valeur, il faut explicitement utiliser mut.

fn main() {    let x = 5; // variable immutable    // x = 6; // erreur de compilation    let mut y = 10;    y += 5; // autorisé car y est mutable    println!("x = {}, y = {}", x, y);}

Une fonction pure n'a pas d'effets secondaires et retourne toujours le même résultat pour les mêmes arguments. Rust permet d'écrire de telles fonctions, mais ne vous y oblige pas — vous pouvez librement mélanger les styles.

fn add(a: i32, b: i32) -> i32 {    a + b // fonction pure}


Les closures — fonctions anonymes

Les closures en Rust sont des fonctions anonymes qui peuvent capturer des variables de la portée environnante. Elles sont définies avec la syntaxe |paramètres| corps. Il existe trois types de closures selon la méthode de capture : par référence (&T), par référence mutable (&mut T) et par valeur (T).

Exemple simple de closure

fn main() {    let factor = 2;    let multiply = |x: i32| x * factor;    println!("{}", multiply(10)); // 20}

Closure avec capture mutable

fn main() {    let mut counter = 0;    let mut increment = || {        counter += 1;        counter    };    println!("{}", increment()); // 1    println!("{}", increment()); // 2}

Les closures sont largement utilisées avec les itérateurs et pour passer un comportement à des fonctions d'ordre supérieur.



Itérateurs et chaînes fonctionnelles

Les itérateurs en Rust sont l'une des abstractions fonctionnelles les plus puissantes. Au lieu de boucles, vous pouvez construire des chaînes de méthodes comme map, filter, fold et autres. Les itérateurs sont paresseux — les calculs n'ont lieu que lors de l'appel d'un consommateur (par exemple, collect ou for_each).

Exemple : filtrage et transformation

fn main() {    let numbers = vec![1, 2, 3, 4, 5, 6];    let result: Vec<i32> = numbers        .iter()        .filter(|&x| x % 2 == 0) // on garde les pairs        .map(|x| x * x)          // on élève au carré        .collect();    println!("{:?}", result); // [4, 16, 36]}

Réduction (fold) — accumulation de valeurs

fn main() {    let numbers = vec![1, 2, 3, 4];    let sum = numbers.iter().fold(0, |acc, x| acc + x);    println!("Somme : {}", sum); // 10}

Les itérateurs rendent le code déclaratif : vous décrivez ce qui doit être fait, et non comment. Cela réduit le risque d'erreurs et améliore la lisibilité.



Filtrage par motif (pattern matching)

La construction match est un élément central du style fonctionnel en Rust. Elle permet de décomposer des structures de données complexes, de traiter les variantes de Option et Result et d'écrire des vérifications exhaustives.

Exemple de base

fn describe_number(n: i32) -> &'static str {    match n {        0 => "zéro",        1 | 2 => "petit nombre",        3..=10 => "nombre moyen",        _ if n < 0 => "négatif",        _ => "grand nombre"    }}

Blogs

Book Recommendations