Reputation: 757
I want to reduce the boilerplate code when handling errors when multiple lines are following each other. I have the following code, working, but I want to know if it is possible to reduce it:
let mut sto = match Storage::new() {
Ok(v) => v,
Err(e) => {
// if needed the error message could be the same as in the next
// bloc, but I want to stop the process here
error!("Failed to open the connection.");
return Err(e);
},
};
// If Ok(), do not care about
if let Err(e) = sto.set("key", item) {
error!("Failed to save the item.");
return Err(e);
}
Note: the error!
macro is a logger macro.
Would it be possible to have something like this ?
if let Err(e) = Storage::new().MAGICAL_FUNC().set("key", item) {
error!("Failed to save the item.");
return Err(e);
}
My searches:
unwrap
as MAGICAL_FUNC cause a panic, so it is not recoverable.and_then
with a closure will prevent if let
from "catching" the Err
of the set
function in the closure.map_err
will not "unwrap" Ok()
. So a new line should be added to "unwrap".Edit: precise error!
macro behaviour
➡️Solution: accepted answer + comment of Masklinn
Upvotes: 0
Views: 571
Reputation: 15125
You can use the ?
operator to make your error-handling code more concise. Example:
struct Storage;
enum Error {
ConnectionFailure,
SaveFailure,
}
impl Storage {
fn new() -> Result<Self, Error> {
Ok(Storage)
// but could possible return
// Err(Error::ConnectionFailure)
}
fn set<T>(&self, key: &'static str, item: T) -> Result<(), Error> {
Ok(())
// but could possible return
// Err(Error::SaveFailure)
}
}
fn save_item<T>(key: &'static str, item: T) -> Result<(), Error> {
let storage = Storage::new()?;
storage.set(key, item)?;
Ok(())
}
fn main() {
match save_item("key", 123) {
Err(Error::ConnectionFailure) => {
// handle connection failure error
},
Err(Error::SaveFailure) => {
// handle save failure error
},
_ => {
// everything went fine catch-all
}
}
}
See also:
Upvotes: 2