[Pre-RFC] Add with() to Option<T> as a flat for_each


#1

I have sometimes found it necessary to do the following:

let x: Option<u32> = foo_bar();
...

if let Some(y) = x {
    fn_call_with(y);
}

Some functions on options are provided, are can be very useful, like and_then or unwrap_or. However, there is no equivalent to a “flat for_each”. So I propose a new function on Option<T> called with of for which takes a closure that is only called if the option has some value.

Example from above:

let x: Option<u32> = foo_bar();
...

x.with(|y| fn_call_with(y));

#2

Of course, this can be done today with x.into_iter().for_each(fn_call_with), as Option implements IntoIterator. There’s also tap::tap_some, of course.


#3

I might be missing something obvious here, but how is this different to Option::map?


#4

This is different for the same reason that for_each is different from map on iterators. for_each is used when no return value is wanted


#5

Thanks for tap::tap_some, would still be nice to have in std


#6

Iterator::map is materially different because it’s lazy, but it should be totally fine for you to use Option::map and drop the return value, which might just be Option<()>.


#7

Yes, Interator::map is lazy, the problem with Option::map is that it requires to return an Option<U> which has to then be written


#8

However, the nice this about the destructing you can move but you cannot move a & or &mut so tap_some is not something that can always be used


#9

No, it doesn’t. Your example works perfectly using map:

fn foo_bar() -> Option<u32> { Some(1) }

fn fn_call_with(v: u32) { println!("{}", v); }

fn main() {
    let x: Option<u32> = foo_bar();
    x.map(|y| fn_call_with(y));
}

#10

The trick here, which is easy to forget, is that map does the wrapping of the closure’s U return value as an Option. You don’t have to return a pre-wrapped Option.

    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
        match self {
            Some(x) => Some(f(x)),
            None => None,
        }
    }

so your map is returning Some(())