Rust est construit sur une gestion explicite des erreurs : les exceptions sont absentes, à la place, on utilise la valeur de retour Result<T, E>. Cela garantit la sécurité et la prévisibilité du code.
Contexte :
De nombreux langages ont emprunté la voie des exceptions, ce qui a conduit à des situations inattendues et à la nécessité de gérer explicitement les exceptions en cours d'exécution. Rust a, dès le début, misé sur le contrôle par le biais des types, toutes les erreurs doivent faire partie de la signature de la fonction.
Problème :
Le principal défi est d'écrire du code dans lequel les erreurs ne sont pas ignorées ou masquées, il n'y a pas de fonctions "qui plantent", mais le code reste compact et lisible. Il est nécessaire de propager correctement les erreurs vers le haut, sans perdre d'informations sur leur type, et sans compliquer la logique.
Solution :
L'outil clé est le type Result<T, E> et l'opérateur ?, qui "déroule" automatiquement le résultat : en cas d'erreur, la fonction sort immédiatement avec le retour de l'erreur, et en cas de succès, la valeur est renvoyée.
Exemple de code :
fn read_number(file: &str) -> Result<i32, std::io::Error> { let content = std::fs::read_to_string(file)?; let num: i32 = content.trim().parse()?; Ok(num) }
Caractéristiques clés :
.map_err() et d'autres méthodes)Peut-on utiliser ? dans des fonctions retournant Unit (void) ?
Non, l'opérateur ? n'est autorisé que dans des fonctions retournant Result ou Option. Si la fonction retourne (), il n'est pas possible d'utiliser ?.
Que se passe-t-il si les types d'erreurs dans plusieurs appels avec ? sont différents ?
Cela entraîne une erreur de compilation : le type d'erreur doit être clairement défini. Il faut soit convertir toutes les erreurs en un seul type via .map_err(), soit utiliser thiserror, ou bien décrire une enveloppe enum au niveau de l'API. Exemple :
fn foo() -> Result<_, MyError> { let a = bar()?; let b = baz().map_err(MyError::Baz)?; Ok(…) }
Pourquoi .unwrap() est-il dangereux dans la logique interne ?
Il est courant de croire à tort que l'on peut utiliser unwrap() sans problème dans le code "principal", "il ne va certainement pas planter". En réalité, même une petite erreur invisible provoquera une panique à l'exécution — ce qui compromettra la sécurité du programme.
unwrap/expect, surtout dans la logique interneDans le code de production, beaucoup de unwrap() ont été laissés après un débogage rapide. En conséquence, l'application plantait à chaque échec de parsing en raison d'une entrée utilisateur incorrecte.
Avantages :
Inconvénients :
Un usage complet de Result<T, E> avec description explicite des erreurs et n'utilisant que ? et .map_err(), en préservant toutes les informations sur l'échec.
Avantages :
Inconvénients :