Programmation fonctionnelle en Rust : idiomes et pratiques

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

Programmation fonctionnelle en Rust : des itérateurs aux monades

Rust est un langage multiparadigme qui combine harmonieusement les styles impératif, orienté objet et fonctionnel. Bien que Rust ne soit pas un langage purement fonctionnel (comme Haskell), son système de types et de possession permet d'écrire un code élégant, sûr et expressif dans un style fonctionnel. Dans cet article, nous allons décortiquer les concepts clés de la programmation fonctionnelle (FP) en Rust : les closures, les itérateurs, le pattern matching, ainsi que le travail avec Option et Result. Ce contenu sera utile aussi bien aux débutants qu'aux développeurs expérimentés souhaitant approfondir les capacités fonctionnelles de Rust.



Closures et expressions lambda

Les closures en Rust sont des fonctions anonymes qui peuvent capturer des variables de la portée environnante. Elles constituent le fondement de l'approche fonctionnelle, permettant de transmettre un comportement comme des données.

La syntaxe des closures est concise : |paramètres| corps. Les closures peuvent être passées à des fonctions, stockées dans des variables et retournées depuis des fonctions. Il est important de se souvenir des trois traits qui contrôlent la capture : Fn (emprunt), FnMut (emprunt mutable) et FnOnce (consommation).

fn main() {    // Closure simple    let add_one = |x: i32| x + 1;    println!("{}", add_one(5)); // 6

// Capture de variable let factor = 10; let multiply = |x| x * factor; println!("{}", multiply(3)); // 30

// Closure avec le trait FnOnce let name = String::from("Rust"); let greet = move || { println!("Bonjour, {}!", name); // name est déplacé }; greet(); // println!("{}", name); // Erreur ! name n'est plus accessible}

Le mot-clé move force la capture par valeur (déplacement), ce qui est souvent nécessaire lors du travail avec la concurrence ou lors du passage d'une closure dans un autre contexte.



Itérateurs : traitement paresseux et chaînes de méthodes

L'un des points forts du style fonctionnel en Rust est le puissant adaptateur d'itérateur. Au lieu de boucles for explicites et de mutations de variables, vous utilisez des chaînes de méthodes : map, filter, fold, collect et autres. Les itérateurs en Rust sont paresseux — ils n'effectuent pas de calculs tant qu'une méthode consommatrice n'est pas appelée (par exemple, collect() ou for_each()).

fn main() {    let numbers = vec![1, 2, 3, 4, 5, 6];

// Approche fonctionnelle : filtrage et transformation let result: Vec<i32> = numbers .iter() // création d'un itérateur .filter(|&x| x % 2 == 0) // on garde uniquement les pairs .map(|x| x * x) // mise au carré .collect(); // collecte dans un vecteur

println!("{:?}", result); // [4, 16, 36]

// Somme avec fold (réduction) let sum = numbers.iter().fold(0, |acc, x| acc + x); println!("Somme : {}", sum); // 21

// Vérification de condition avec any et all let has_even = numbers.iter().any(|x| x % 2 == 0); println!("Y a-t-il des pairs : {}", has_even); // true}

L'utilisation des itérateurs rend le code déclaratif, lisible et moins sujet aux erreurs liées à l'indexation et aux limites des tableaux. Le compilateur Rust optimise souvent les chaînes d'itérateurs en code machine efficace, comparable aux boucles manuelles.



Pattern matching et déstructuration

Le pattern matching (match) est le cœur du contrôle de flux fonctionnel en Rust. Il permet de traiter en toute sécurité toutes les variantes possibles des données, en particulier en combinaison avec les types de données algébriques (enum). Les motifs peuvent être imbriqués, inclure des conditions (guards) et déstructurer des structures, des tuples et des énumérations.

enum Message {    Quit,    Move { x: i32, y: i32 },    Write(String),    ChangeColor(i32, i32, i32),}

fn handle_

Blogs

Book Recommendations