I posted this originally on the Rust Users Forum.
Option combinator methods make working with Option
s much smoother, but I found a case which isn't covered by them.
It is when I have two Option<T>
's and I want to get an Option<T>
that has a Some
if either of the inputs is Some
, and combine the values if both are Some
. So, it would be similar to Option::or()
, but when both inputs are Some
, it would call a closure to determine the output.
It's easier to describe what I mean with a snippet of code:
fn merge_with<T, F>(a: Option<T>, b: Option<T>, f: F) -> Option<T>
where F: FnOnce(T, T) -> T
{
match (a, b) {
(None, None) => None,
(Some(v), None) => Some(v),
(None, Some(v)) => Some(v),
(Some(v1), Some(v2)) => Some(f(v1, v2))
}
}
It could be used to perform aggregation operations on Option
-wrapped values without unwrapping them first.
I can imagine two kinds of operations being used with this:
-
An operation that selects one of its operands:
let a = Some(2); let b = Some(5); let greater = a.merge_with(b, i32::max);
-
Or, an operation that somehow merges them:
use core::ops::Add; let a = Some(2); let b = Some(5); let sum = a.merge_with(b, Add::add);
As pointed out by @kpreid on the original post, it's currently possible to achieve the same effect without a match
by converting to iterators:
[a, b].into_iter().flatten().reduce(f)
or
a.into_iter().chain(b).reduce(f)
There was also a discussion about some similar thing in Haskell (which I'm not qualified to talk about), see the original post.
I see several use cases for this, but what do you think? Would it be useful? Would it be worthwhile to add this to std
? I see that this is a minor feature, but so are many other combinators, and I think it would improve the ergonomics of working with Option
-wrapped values.
Also, I couldn't come up with a better name than merge_with
but I feel like it's very generic, so if you have a more descriptive name for this, don't keep it to yourself.