Introduction : la philosophie de la gestion des erreurs en Rust
Contrairement à de nombreux langages utilisant des exceptions (Java, Python, C++), Rust n'utilise pas la construction classique try/catch. Le langage propose plutôt une approche plus explicite et type-safe. Les erreurs en Rust ne sont pas des flux de contrôle cachés, mais des valeurs de retour. Cela rend le code prévisible et protège contre les pannes « silencieuses ».
Rust dispose de deux types principaux pour représenter les situations d'erreur :
- Result<T, E> — pour les erreurs récupérables (erreurs d'entrée-sortie, d'analyse syntaxique, de logique métier).
- Option<T> — pour l'absence de valeur (analogue à null, mais sécurisé).
Dans cet article, nous allons voir comment travailler avec ces types, comment les substituer au monde du try/catch, et comment écrire du code fiable en Rust.
1. Result<T, E> : l'outil principal de gestion des erreurs
Le type Result est une énumération avec deux variantes : Ok(T) (succès) et Err(E) (erreur). Il est utilisé dans la plupart des fonctions qui peuvent échouer.
1.1. Création et retour d'un Result
use std::fs::File;use std::io::Read;
fn read_file(path: &str) -> Result<String, std::io::Error> { let mut file = File::open(path)?; // l'opérateur ? — analogue à try ! let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents)}Ici, l'opérateur ? est un élément clé. Il fonctionne comme try dans d'autres langages : si le résultat est Err, la fonction retourne immédiatement cette erreur. Si c'est Ok, il extrait la valeur.
1.2. Gestion avec match
La manière la plus explicite est d'utiliser match :
let result = read_file("config.txt");
match result { Ok(content) => println!("Fichier lu : {}", content), Err(e) => eprintln!("Erreur : {}", e),}C'est un analogue de try/catch, mais plus flexible et contrôlé.
1.3. Méthodes auxiliaires
.unwrap()— panique en cas d'erreur (uniquement pour les prototypes)..expect(msg)— panique avec un message personnalisé..unwrap_or(default)— retourne une valeur par défaut..is_ok()/.is_err()— vérification de l'état.
2. Option<T> : travail sécurisé avec l'absence de valeur
Option est une autre énumération avec les variantes Some(T) et None. Elle remplace null et nullptr, éliminant les erreurs de déréférencement de pointeur nul.
2.1. Exemple d'utilisation
fn find_user(id: u32) -> Option<String> { if id == 1 { Some("Alice".to_string()) } else { None }}
let user = find_user(2);println!("Utilisateur : {}", user.unwrap_or("Invité".to_string()));2.2. Combinaison avec Result
Il est fréquent de convertir Option en Result pour un traitement uniforme :
fn get_user_name(id: u32) -> Result<String, String> { find_user(id).ok_or("Utilisateur non trouvé".to_string())}La méthode .ok_or() transforme Some en Ok, et None en Err.
3. L'opérateur ? : un remplacement élégant de try/catch
L'opérateur ? est un sucre syntaxique qui dépaquette automatiquement un Result ou un Option. Il n'est disponible que dans les fonctions retournant le type correspondant.
3.1. Exemple avec une chaîne d'appels
use std::num::ParseIntError;
fn parse_and_add(a: &str, b: &str) -> Result<i32, ParseIntError> { let x: i32 = a.parse()?; let y: i32 = b.parse()?; Ok(x
```