rust - resfriada - remedios caseros para la alergia nasal
¿Cómo detengo la iteración y devuelvo un error cuando Iterator:: map devuelve un Result:: Err? (2)
Esta respuesta se refiere a una versión anterior a la versión 1.0 de Rust y se eliminaron las funciones necesarias
Puede usar la función std::result::fold
para esto. Deja de iterar después de encontrar el primer Err
.
Un programa de ejemplo que acabo de escribir:
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))
}
}
Salida:
Ok([1, 2, 3])
Err(-2 is not positive!)
Tengo una función que devuelve un Result
:
fn find(id: &Id) -> Result<Item, ItemError> {
// ...
}
Luego otro usándolo así:
let parent_items: Vec<Item> = parent_ids.iter()
.map(|id| find(id).unwrap())
.collect();
¿Cómo manejo el caso de falla dentro de cualquiera de las iteraciones del map
?
Sé que podría usar flat_map
y en este caso los resultados del error serían ignorados :
let parent_items: Vec<Item> = parent_ids.iter()
.flat_map(|id| find(id).into_iter())
.collect();
El iterador del resultado tiene 0 o 1 elementos dependiendo del estado de éxito, y flat_map
lo filtrará si es 0.
Sin embargo, no quiero ignorar los errores. En su lugar, quiero hacer que todo el bloque de código se detenga y devuelva un nuevo error (basado en el error que apareció en el mapa, o simplemente reenviar el error existente).
¿Cómo manejo esto en Rust?
Result
implementa FromIterator
, por lo que puede mover el Result
exterior y los iteradores se encargarán del resto (incluida la detención de la iteración si se encuentra un error).
#[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);
}