10

I am confused about the Some(T) keyword.

I want to check for two variables, if the value is defined (not None). If that is the case, the value of this variables is processed.

I know the match pattern which works like this:

match value {
    Some(val) => println!("{}", val),
    None => return false,
}

If I use this pattern, it will get very messy:

match param {
    Some(par) => {
        match value {
            Some(val) => {
                //process
            },

            None => return false,
        }
    },

    None => return false,
}

This can't be the right solution.

The is a possibility, to ask if the param and value is_some() That would effect code like that:

if param.is_some() && value.is_some() {
    //process
}

But if I do it like that, I always have to unwrap param and value to access the values.

I thought about something like this to avoid that. But this code does not work:

if param == Some(par) && value == Some(val) {
    //process
}

The idea is that the values are accessible by par and val like they are in the match version.

Is there any solution to do something like this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
NelDav
  • 785
  • 2
  • 11
  • 30
  • 3
    Did you already see `if let Some(T)`? https://doc.rust-lang.org/book/ch06-03-if-let.html It's useful when you just need value and "ignore" `None` value. – Đorđe Zeljić Apr 06 '20 at 22:05
  • 4
    Nitpick: `Some` isn't a keyword in Rust. The language automatically pulls parts of the standard library into scope: https://doc.rust-lang.org/std/prelude/index.html and `std::option::Option::{Some, None}` is part of that list. – Optimistic Peach Apr 06 '20 at 23:09
  • Thank you both of you good to know. – NelDav Apr 06 '20 at 23:20
  • See also [What's the idiomatic way to handle multiple `Option` in Rust?](https://stackoverflow.com/q/50731439/155423) – Shepmaster Apr 07 '20 at 01:36

3 Answers3

17

If I have several Option values to match, I match on a tuple of the values:

enum Color {
    Red,
    Blue,
    Green,
}

fn foo(a: Option<Color>, b: Option<i32>) {
    match (a, b) {
        (Some(Color::Blue), Some(n)) if n > 10 => println!("Blue large number"),
        (Some(Color::Red), _) => println!("Red number"),
        _ => (),
    }
}

fn main() {
    foo(Some(Color::Blue), None);
    foo(Some(Color::Blue), Some(20));
}         

This allows me to match the combinations that are interesting, and discard the rest (or return false, if that is what you want to do).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mats Kindahl
  • 1,863
  • 14
  • 25
8

If your function is processing multiple Option values, and would like to discard them if they're not Some, your function could return an Option itself:

fn foo(param: Option<usize>, value: Option<usize>) -> Option<usize> {
    let result = param? + value?;
    Some(result)
}

This will short-circuit the function in case there's a None value stored in either param or value.

Please read the book for more information on the ? operator.

If your function can't return an Option, you can still get away with destructuring using if let or match:

let x = if let (Some(p), Some(v)) = (param, value) {
    p + v
} else {
    return 0;
}
let x = match (param, value) {
    (Some(p), Some(v)) => p + v,
    (Some(p), _) => p,
    (_, Some(v) => v,
    _ => return 0,
}

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Optimistic Peach
  • 3,862
  • 2
  • 18
  • 29
2

There's a couple more alternatives not yet listed:

If you're willing to use experimental features (and hence the nightly compiler) you can use a try block as an alternative of extracting a function.

#![feature(try_blocks)]

fn main() {
    let par: Option<f32> = Some(1.0f32);
    let value: Option<f32> = Some(2.0f32);

    let x: Option<f32> = try { par? + value? };

    println!("{:?}", x);
}

Another alternative is to use map which only applies if the value is not None

let x: Option<f32> = par.map(|p| value.map(|v| p + v));
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Michael Anderson
  • 70,661
  • 7
  • 134
  • 187