Is there a less verbose way to extract values from Options in Rust
You are looking for Option::ok_or
. It lets you map an Option
into a Result
with the provided error. Combined with the ?
operator you clean things up nicely:
fn foo() -> Result<i32, String> {
let cur = something_that_returns_an_option().ok_or("some error")?;
Ok(cur + 1)
}
Playground
Option::ok_or_else
might also be helpful, as it evaluates the error branch lazily.
In your example you want to not just continue, break or return a regular value, but return an error. For that particular case, the Aiden4's answer is the way to go. But I've been in situations where I want to unwrap or (in the case of None
) directly continue
, break
or return
a non-error value. Rust (still) doesn't provide a short and concise way to do exactly that.
Here is a "one-liner" which kinda does the trick, but is still a bit verbose:
let v = if let Some(d) = some_option_value { d } else { continue; };
If you want a shorter solution, here are two options...
A macro
You can write a macro like this:
macro_rules! unwrap_or {
($e:expr, $or_do_what:expr) => {
if let Some(d) = $e { d } else { $or_do_what }
};
}
That will allow you to write code like this:
let options = vec![Some(74), None, Some(9)];
for o in options {
let v = unwrap_or!(o, continue);
// ...
}
That's a trivial example, but I think the biggest benefit can come if you need to perform multiple checks, so that instead of writing something "idiomatic" like this:
for thing in things {
if let Some(a) = thing {
// ...
if let Some(b) = a.another_opt {
// ...
if let Some(c) = a.yet_another_opt {
// ...
}
}
}
}
, you can simplify the code by avoiding the nesting of multiple blocks like this:
for thing in things {
let a = unwrap_or!(thing, continue);
// ...
let b = unwrap_or!(a.another_opt, continue);
// ...
let c = unwrap_or!(a.yet_another_opt, continue);
// ...
}
Whether that's a good practice is subjective, of course.
let...else (unstable)
There is an unstable let...else
feature, which is intended to solve the problem. Example:
#![feature(let_else)]
...
let options = vec![Some(74), None, Some(9)];
for o in options {
let Some(v) = o else { continue };
println!("v = {v}");
}