L'utilisation du type Result est devenue l'une des approches clés pour la gestion des erreurs en Rust. Historiquement, dans de nombreux langages — comme C — les erreurs étaient souvent signalées par des valeurs de retour spéciales ou des variables globales, ce qui entraînait des erreurs fréquentes en ignorant ces signaux. Rust a opté pour un typage explicite des erreurs grâce à l'énumération Result<T, E>, ce qui rend impossible l'ignorance accidentelle d'une erreur — le compilateur oblige à traiter les deux branches (succès et échec).
Problème : Il était nécessaire de rendre le traitement des erreurs aussi sûr et lisible que possible, d'éliminer les erreurs "cachées", ainsi que d'améliorer la fiabilité du code sans avoir besoin d'utiliser des exceptions.
Solution : Result<T, E> est une énumération avec deux variantes : Ok(T) en cas de succès et Err(E) en cas d'erreur. Cela oblige à traiter explicitement les erreurs, ou à les ignorer clairement à l'aide de unwrap ou à s'attendre à des panics. De plus, l'opérateur ? rend les modèles courants de propagation des erreurs concis.
Exemple de code :
use std::fs::File; use std::io::{self, Read}; fn read_file(path: &str) -> Result<String, io::Error> { let mut file = File::open(path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) }
Caractéristiques clés :
?.Peut-on toujours utiliser l'opérateur ? pour propager automatiquement l'erreur vers le haut ?
Non, seulement si le type d'erreur de la fonction correspond au type de l'expression à droite du ?. Si les types ne sont pas compatibles, il est nécessaire de faire une conversion explicite de l'erreur à l'aide de la méthode .map_err() ou de son propre type.
Exemple de code :
fn f() -> Result<(), String> { let _f = File::open("foo").map_err(|e| e.to_string())?; Ok(()) }
Peut-on laisser le résultat de Result inutilisé si l'on ne s'intéresse pas aux erreurs ?
Non, le compilateur générera un avertissement ou une erreur si le résultat du type Result n'est pas traité. Soit vous appelez .unwrap(), soit vous appelez explicitement .ok()/.err()/let _ = ... ou vous journalisez correctement l'erreur.
Que se passera-t-il si vous appelez .unwrap() sur un Result avec une erreur ?
Un panic sera déclenché et l'exécution du programme sera interrompue, cela conduit généralement à une fermeture brutale. Par conséquent, unwrap() n'est acceptable que lorsqu'on garantit le succès.
let _ = ...;) sans journalisationUn développeur a décidé de lire une configuration à partir d'un fichier et a utilisé unwrap() sur le résultat de la lecture.
Avantages :
Inconvénients :
Les erreurs lors de la lecture de la configuration sont journalisées et remontées le long de la pile d'appels à l'aide de Result + opérateur ?.
Avantages :
Inconvénients :