Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the idiomatic way to do something when an Option is either None, or the inner value meets some condition?

Tags:

rust

Is there a more idiomatic way to express something like the following?

fn main() {
    let mut foo: Option<u8> = None;
    match foo {
        Some(foo_val) if ! (foo_val < 5) /* i.e. the negation of my acceptance condition */ => {}
        _ => { foo.replace(5); }
    }
}

It seems like most of the time there's an alternative to having an arm that doesn't do anything, but I've been unable to find one for this particular case.

What I'd like to say is the more direct if foo.is_none() || /* some way to extract and test the inner value */ { ... }, or perhaps some chaining trick that's eluding me.

like image 314
thisisrandy Avatar asked Aug 31 '25 22:08

thisisrandy


2 Answers

EDIT: correct solution for Rust >= 1.82 https://stackoverflow.com/a/79158152/2408867


//        in None case
//             │       in Some(_) case
//            ┌┴─┐  ┌───────────────────┐    
if foo.map_or(true, |foo_val| foo_val < 5) {
    // ...
}

For more information see Option::map_or.

like image 147
Lukas Kalbertodt Avatar answered Sep 04 '25 08:09

Lukas Kalbertodt


There are many ways to do it. One of the simplest (and arguably most readable) is something like this:

if foo.unwrap_or(0) < 5 {
    ...
}

The above will be true in both cases:

  • when foo is Some with a value smaller than 5;
  • when foo is None.

In some more complex scenarios, where the "default" value needs to be calculated and performance is critical, you might want to consider unwrap_or_else.

As Lukas suggested, the map_or method can also be used. Note that arguments passed to map_or are eagerly evaluated, so if performance is critical, you might want to consider map_or_else as an alternative.

Rust 1.70+

The is_some_and method has been stabilized in Rust 1.70. Here is an example:

if name.is_some_and(|s| s.len() > 50) {
    println!("This is a long name!");
}

In many cases that should be more readable than map_or / map_or_else.

like image 42
at54321 Avatar answered Sep 04 '25 07:09

at54321