Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any built in way to "combine" two Options?

In the following sample program, is there any way I could avoid having to define map2?

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    match a {
        Some(x) => match b {
            Some(y) => Some(f(x, y)),
            None => None,
        },
        None => None,
    }
}

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| {
        a + b
    };
    let res = map2(f, a, b);
    println!("{:?}", res);
    // prints Some(15)
}

For people who also speak Haskell, I guess this question could also be phrased as "Is there any tool we can use instead of liftM2 in Rust?"

like image 370
Erik Vesteraas Avatar asked Nov 18 '15 12:11

Erik Vesteraas


3 Answers

I don't believe there's a direct function equivalent to liftM2, but you can combine Option::and_then and Option::map like this:

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| {
        a + b
    };

    println!("{:?}", a.and_then(|a| b.map(|b| f(a, b))));
}

Output:

Some(15)
like image 77
Dogbert Avatar answered Oct 07 '22 03:10

Dogbert


As of Rust 1.46.0, you can use Option::zip:

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    match a.zip(b) {
        Some((x, y)) => Some(f(x, y)),
        None => None,
    }
}

This can be combined with Option::map, as shown in other answers:

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    a.zip(b).map(|(x, y)| f(x, y))
}
like image 16
Shepmaster Avatar answered Oct 07 '22 01:10

Shepmaster


I don't know if you can get down to one line (Edit: oh the accepted answer gets it down to one line nicely), but you can avoid the nested match by matching on a tuple:

let a = Some(5);
let b = Some(10);
let f = |a, b| {
    a + b
};
let res = match (a, b) {
    (Some(a), Some(b)) => Some(f(a, b)),
    _ => None,
};
println!("{:?}", res);
// prints Some(15)
like image 11
Jack O'Connor Avatar answered Oct 07 '22 01:10

Jack O'Connor