Introduction
Dans ce laboratoire, nous allons voir comment définir un type d'erreur personnalisé en Rust et les principales caractéristiques qui font d'un bon type d'erreur, telles que la représentation de différentes erreurs avec le même type, la fourniture de messages d'erreur clairs, la comparaison facile avec d'autres types et la capacité de conserver des informations sur l'erreur. Nous allons également examiner un exemple de code qui démontre l'implémentation d'un type d'erreur personnalisé et son utilisation dans des scénarios de gestion d'erreurs.
Note : Si le laboratoire ne spécifie pas de nom de fichier, vous pouvez utiliser n'importe quel nom de fichier que vous voulez. Par exemple, vous pouvez utiliser
main.rs, le compiler et l'exécuter avecrustc main.rs &&./main.
Définition d'un type d'erreur
Parfois, il est simplifié le code en masquant toutes les différentes erreurs avec un seul type d'erreur. Nous allons le montrer avec une erreur personnalisée.
Rust nous permet de définir nos propres types d'erreur. En général, un "bon" type d'erreur :
- Représente différentes erreurs avec le même type
- Présente de bons messages d'erreur à l'utilisateur
- Est facile à comparer avec d'autres types
- Bon :
Err(EmptyVec) - Mauvais :
Err("Please use a vector with at least one element".to_owned())
- Bon :
- Peut conserver des informations sur l'erreur
- Bon :
Err(BadChar(c, position)) - Mauvais :
Err("+ cannot be used here".to_owned())
- Bon :
- Se compose bien avec d'autres erreurs
use std::fmt;
type Result<T> = std::result::Result<T, DoubleError>;
// Définissons nos types d'erreur. Ils peuvent être personnalisés pour nos cas de gestion d'erreurs.
// Maintenant, nous serons en mesure d'écrire nos propres erreurs, nous référer à une implémentation d'erreur sous-jacente
// ou faire quelque chose au milieu.
#[derive(Debug, Clone)]
struct DoubleError;
// La génération d'une erreur est complètement séparée de la manière dont elle est affichée.
// Il n'est pas nécessaire de s'inquiéter de brouiller une logique complexe avec le style d'affichage.
//
// Notez que nous ne stockons aucune information supplémentaire sur les erreurs. Cela signifie que nous ne pouvons pas indiquer
// quelle chaîne a échoué à être analysée sans modifier nos types pour transporter cette information.
impl fmt::Display for DoubleError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid first item to double")
}
}
fn double_first(vec: Vec<&str>) -> Result<i32> {
vec.first()
// Changez l'erreur en notre nouveau type.
.ok_or(DoubleError)
.and_then(|s| {
s.parse::<i32>()
// Mettez à jour également le nouveau type d'erreur ici.
.map_err(|_| DoubleError)
.map(|i| 2 * i)
})
}
fn print(result: Result<i32>) {
match result {
Ok(n) => println!("The first doubled is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
let numbers = vec!["42", "93", "18"];
let empty = vec![];
let strings = vec!["tofu", "93", "18"];
print(double_first(numbers));
print(double_first(empty));
print(double_first(strings));
}
Sommaire
Félicitations ! Vous avez terminé le laboratoire Définition d'un type d'erreur. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.