Early return on Option::None

I'm wondering if there is a cleaner way to do the following:

fn foo(option: Option<Foo>) -> Bar {
    if option.is_none() {
        // do stuff and return
    }

    let some = option.unwrap();

    // do other stuff and return something else
}

I find match and if let statements result in unnecessary indentation in cases like these

Using unwrap is error-prone because you'll lose context as soon as there's some separation between it and the check fir the None case.

fn foo(option: Option<Foo>) -> Bar {
    let Some(some) = option else {
        // do stuff and return
    };
    // do other stuff and return something else
}
11 Likes

Once, they said: use structured programming. And they say humans struggle with negated expressions. Then there are the functional folks with their everything is an expression mindset, inspiring Rust to adopt some of their elegant conveniences:

fn foo(option: Option<Foo>) -> Bar {
    if let Some(some) = option {
        do_something_and_create_bar()  // Note the missing semicolon
    } else {
        create_some_other_bar() // Look ma, no return!
    }
}

...but the early return starts popping up everywhere, undermining the elegance.

:wink:

The idiomatic way would be to use a match expression, or the combinators on Option, like map/and_then/map_or_else/unwrap_or/etc

I suggest you avoid unwrap() completely, instead structuring your code so that it never needs to be called. In the rare cases where you have no choice, use expect() instead and document your expectation as to why the value is guaranteed to be Some or Ok.

1 Like