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}");
}