La gestion des erreurs en Rust est explicite et idiomatique : pas d’exceptions cachées, pas de valeurs null inattendues. Rust distingue deux catégories d’erreurs — les erreurs irrécupérables (panics) et les erreurs récupérables (Result) — et fournit des outils élégants pour les gérer sans verbosité excessive. Dans cette unité, vous apprendrez à écrire du code qui gère les erreurs de façon propre et lisible.
Panic ! : les erreurs irrécupérables
Un panic est une erreur fatale : le programme s’arrête immédiatement avec un message d’erreur et une trace de la pile. On l’utilise pour les invariants violés, les bugs de programmation, jamais pour les erreurs prévisibles.
fn diviser(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("Division par zero !"); // arrêt immédiat
}
a / b
}
// Accès hors limites
let v = vec![1, 2, 3];
// v[10]; // thread 'main' panicked: index out of bounds
Result<T, E> : les erreurs récupérables
Result est un enum à deux variantes : Ok(valeur) en cas de succès, et Err(erreur) en cas d’échec. Toute fonction pouvant échouer retourne un Result.
use std::fs;
use std::io;
fn lire_fichier(chemin: &str) -> Result<String, io::Error> {
let contenu = fs::read_to_string(chemin)?; // ? propage l'erreur
Ok(contenu)
}
fn main() {
match lire_fichier("config.txt") {
Ok(contenu) => println!("Contenu : {}", contenu),
Err(e) => println!("Erreur : {}", e),
}
}
L’opérateur ? : propagation élégante
L’opérateur ? est du sucre syntaxique pour le pattern match sur Result : si c’est Ok, il extrait la valeur ; si c’est Err, il retourne immédiatement l’erreur. Il transforme le code verbeux en code lisible.
// Sans ? (verbeux)
fn lire_v1(chemin: &str) -> Result<u32, io::Error> {
let contenu = match fs::read_to_string(chemin) {
Ok(c) => c,
Err(e) => return Err(e),
};
Ok(contenu.len() as u32)
}
// Avec ? (idiomatique)
fn lire_v2(chemin: &str) -> Result<u32, io::Error> {
let contenu = fs::read_to_string(chemin)?;
Ok(contenu.len() as u32)
}
Option<T> : les valeurs absentes
Option est l’alternative de Rust à null. Une valeur de type Option<T> est soit Some(valeur), soit None. Le compilateur force la gestion des deux cas, éliminant les NullPointerExceptions.
fn trouver_prefixe(reference: &str) -> Option<&str> {
if reference.contains("DOC") {
Some(reference.split("--").next().unwrap_or(reference))
} else {
None
}
}
fn main() {
let r = "DOC-2024-001";
match trouver_prefixe(r) {
Some(p) => println!("Préfixe : {}", p),
None => println!("Pas de préfixe"),
}
// Méthodes utilitaires
let valeur = trouver_prefixe("DOC-001").unwrap_or("INCONNU");
let majuscule = trouver_prefixe("DOC-001").map(|p| p.to_uppercase());
println!("{} / {:?}", valeur, majuscule);
}
Créer ses types d’erreur
Pour les projets plus importants, on crée ses propres types d’erreur avec un enum et on implémente le trait std::error::Error. La crate thiserror simplifie cette tâche :
use thiserror::Error;
#[derive(Error, Debug)]
enum ErreurRef {
#[error("Format invalide : {0}")]
FormatInvalide(String),
#[error("Référence non trouvée")]
NonTrouvee,
#[error("Erreur I/O : {0}")]
Io(#[from] std::io::Error),
}
fn analyser_ref(s: &str) -> Result<u32, ErreurRef> {
if s.is_empty() {
return Err(ErreurRef::FormatInvalide(s.to_string()));
}
s.parse::<u32>().map_err(|_| ErreurRef::FormatInvalide(s.to_string()))
}
panic!pour les bugs irrécupérables,Resultpour les erreurs prévisibles- L’opérateur
?propage les erreurs élégamment dans les fonctions qui retournentResult Option<T>remplace null et force la gestion du cas absent à la compilation- Créez vos propres types d’erreur avec
thiserrorpour un code expressif
📚 Formation : Rust : Développer des utilitaires système

-
Add a note