Building map_ok - Closure Ownership Question

As a quick knowledge check, I decided to implement a version of map_ok - a map function that works on iterators with Result<T,E> and can perform some operation, producing Result<U,E>

Here was my implementation:

pub trait MapHelper: Iterator {
    fn map_ok<F, T, E, U>(self, f: F) -> impl Iterator<Item = Result<U, E>> 
        where 
            Self: Iterator<Item = Result<T, E>> + Sized,
            F: Fn(T) -> U,
    {
        self.map(move |x| x.map(|y| f(y)))
    }
}

impl<T:Iterator> MapHelper for T {}

I wanted to ask, in general, if this is a reasonable implementation.

Also, if I'm reading the compiler messages correctly, move is necessary here because the closure only captures f by reference, and the closure passed to map may live longer than the function map_ok (so we need to switch to using a move closure). Is this the correct?

2 Likes

FnMut is more flexible for the consumer.

The phrasing of the error message is a bit odd, but you're basically trying to return a reference to a local (f) without move.

In your case, it's not a matter of "may" as much as of "most certainly will":

pub trait MapHelper: Sized {
    fn map_ok<F, T, E, U>(self, f: F) -> impl Iterator<Item = Result<U, E>> 
        where 
            Self: Iterator<Item = Result<T, E>>,
            F: Fn(T) -> U,
    {   
        // local scope, no "move" necessary
        let vec: Vec<_> = std::iter::empty::<Result<T, E>>()
            .map(|x| x.map(&f)) 
            .collect();
        // closure *will* outlive the fn() on return,
        // the "move" is therefore required
        self.map(move |x| x.map(&f))
    }
}