Idiomatic way to merge two Options

Suppose I have two Option<T>, and a function to merge two Ts:

let a: Option<T> = ...;
let b: Option<T> = ...;
let f: fn(T, T) -> T = ...;

Is there some clean way to merge them using that function, instead of writing the following code:

let c = match a {
  None => b,
  Some(a_value) => match b {
    None => Some(a_value),
    Some(b_value) => Some(f(a_value, b_value)),
  }
};

I didn't find my desired function in the doc of Option. There is zip_with, but it isn't doing what I want.

You can collapse both those matches into one match on a tuple:

match (opt_a, opt_b) {
    (Some(a), Some(b)) => Some(f(a,b)),
    (opt_a, opt_b) => opt_a.or(opt_b)
}
5 Likes

I'd just extract this merging logic into separate function, like this:

fn merge<T>(first: Option<T>, second: Option<T>, merger: fn(T, T) -> T) -> Option<T> {
    let first = first?;
    let second = second?;
    Some(merger(first, second))
}

Playground

1 Like

Why bother with the bindings? You could just write

fn merge<T>(first: Option<T>, second: Option<T>, merger: fn(T, T) -> T) -> Option<T> {
    Some(merger(first?, second?))
}

I want merge(Some(t0), None) to be Some(t0), but I think you're giving None.

? always returns when encountering None, i.e. (a?, b?) where a & b: Option<T> is of the type (T, T).