pub fn bar() -> Result<T, Vec<E>> { ... }
pub fn bar2() -> Result<T2, Vec<E>> { .... }
pub fn some_func() -> Result<T, Vec<E>> {
let e = E::new(...);
{
anytime here, when we use ? on something that returns a Result<T, Vec<E>>,
I would like to do a Vec::push(_, e) to the end of the error
}
}
It is possible to achieve the above with a 'wrapper' function. Is there something more elegant ?
pub fn some_func() -> Result<T, Vec<E>> {
let e = E::new(...);
let save_err = |mut v: Vec<E>| { v.push(e.clone()); v };
{
let _t2 = bar2().map_err(save_err)?;
let tee = bar().map_err(save_err)?;
Ok(tee)
}
}
Maybe a vec of errors is the correct semantics, for example they might be copying a list of files and want the status of each file after the copy, in which case it makes sense to have a vector of the errors that could happen. You're correct that the vector itself could be wrapped in another error depending on what OP is doing
Can you expand on this? What exactly are you suggesting? I'm not very detail oriented when it comes to errors; I tend to have on Err enum per crate, and the main goal of this Vec is so keep a 'stack' of what actions (from general to narrow) prog was trying to perform when it ran into error.
When you ? the Err::<_, E1>(e1) within the function returning Result<_, E2>, the value e1 is converted to E2 type using From impl. The common impl is to wrap the e1 within the E2 with some additional data and/or variants. thiserror crate makes it really easier with its #[from] attribute. Another case of this pattern is anyhow::Context which allows to wrap the given error with some contexture message.
This depends on E1 and E2 being different types right? So I would need to have very fine grained errors and a 'hierarchy' of error types. Is that correct ?