Use ? operator inside map function


#1

Please consider the following example:

fn t() -> Option<()> {
    let a = [Some(0), None, Some(2)];
    let mut iter = a
                    .into_iter()
                    .map(|x| x?)
                    .for_each(|x| println!("{}", x));
    Some(())
}

fn main() {
    println!("{}", t().is_none())
}

I know why it is not compiled, however, I am looking for a solution to make it possible to use ? operator in these cases.


#2

What is it that you actually want to do? The following compiles:

let mut iter = a
                .into_iter()
                .map(|x| { Some((*x)?) })
                .for_each(|x| println!("{:?}", x));

but it isn’t very useful. The above turns the &Option<i32> into an Option<i32> via *x, returns None if that results in None, and otherwise wraps the value in Some, so it’s essentially .map(|x| *x).


#3

I wanted to unwrap() all elements in map (or return from t function if an element is None), then use the unwraped elements in for_each


#4

A normal for loop seems just as ergonomic here:

for x in a.into_iter().cloned() {
    println!("{}", x?);
}                    

#5

I believe you are looking for the filter_map iterator adapter. This method will filter out all elements that return None and keep those that return Some(_) and returns the item inside the Some(_).

It can be used like this:

fn t() -> Option<()> {
    let a = [Some(0), None, Some(2)];
    let iter = a.into_iter()
        .filter_map(|x| *x)
        .for_each(|x| println!("{}", x));
    Some(())
}

fn main() {
    println!("{}", t().is_none())
}

Try on Rust Playground


#6

I was going to suggest filter_map as well until I saw @yaa110 mentioning that they want to return from t() when a None is seen - that’s different semantic from filter_map.


#7

For cases where you return Result, it’s useful to know that .collect() can take iterator of Result<T,E> and collect into Result<Vec<T>, E>, so you can then use ? on the collection:

a.into_iter() 
    .map(|x| x.ok_or(NoneError))
    .collect::<Result<Vec<_>,_>>()?

#8

If you’re on nightly:

fn t() -> Option<()> {
    let a = [Some(0), None, Some(2)];
    a
        .iter()
        .cloned()
        .try_for_each(|x| Some(println!("{}", x?)))
}

https://play.rust-lang.org/?gist=d99506d0f59b68907017b3d84c42be5e&version=nightly


#9

Works with options too!

fn main() {
    let a = vec![Some(0), None, Some(2)];
    let xs = a.into_iter().collect::<Option<Vec<_>>>();
    println!("{:?}", xs)
}

playground


#10

Update: try_for_each (& friends) are now in FCP for stabilization: