J'ai une fonction qui retourne un Result
:
fn find(id: &Id) -> Result<Item, ItemError> {
// ...
}
Puis un autre l'utilisant comme ceci:
let parent_items: Vec<Item> = parent_ids.iter()
.map(|id| find(id).unwrap())
.collect();
Comment gérer le cas d'échec dans l'une des itérations map
?
Je sais que je pourrais utiliser flat_map
et dans ce cas, les résultats d'erreur seraient ignorés:
let parent_items: Vec<Item> = parent_ids.iter()
.flat_map(|id| find(id).into_iter())
.collect();
L'itérateur de Result
a 0 ou 1 éléments selon l'état de réussite, et flat_map
le filtrera si c'est 0.
Cependant, je ne veux pas ignorer les erreurs, je veux plutôt faire arrêter le bloc de code entier et renvoyer une nouvelle erreur (basée sur l'erreur qui est survenue dans la carte, ou simplement transmettre le erreur existante).
Comment gérer au mieux cela dans Rust?
Result
implémente FromIterator
, vous pouvez donc déplacer le Result
à l'extérieur et les itérateurs se chargeront du reste (y compris l'arrêt de l'itération si une erreur est trouvée ).
#[derive(Debug)]
struct Item;
type Id = String;
fn find(id: &Id) -> Result<Item, String> {
Err(format!("Not found: {:?}", id))
}
fn main() {
let s = |s: &str| s.to_string();
let ids = vec![s("1"), s("2"), s("3")];
let items: Result<Vec<_>, _> = ids.iter().map(find).collect();
println!("Result: {:?}", items);
}
Cette réponse se rapporte à une version antérieure à 1.0 de Rust et les fonctions requises ont été supprimées
Vous pouvez utiliser std::result::fold
fonction pour cela. Il cesse d'itérer après avoir rencontré le premier Err
.
Un exemple de programme que je viens d'écrire:
fn main() {
println!("{}", go([1, 2, 3]));
println!("{}", go([1, -2, 3]));
}
fn go(v: &[int]) -> Result<Vec<int>, String> {
std::result::fold(
v.iter().map(|&n| is_positive(n)),
vec![],
|mut v, e| {
v.Push(e);
v
})
}
fn is_positive(n: int) -> Result<int, String> {
if n > 0 {
Ok(n)
} else {
Err(format!("{} is not positive!", n))
}
}
Production:
Ok([1, 2, 3])
Err(-2 is not positive!)