Cannot return value referencing local variable in closure

Hello! I am writing my pet app and spent a lot of time trying to figure out why this error occurs. I am building a future stream of ip's, which should ping each ip in parrallel, so I guess i must use buffer_unordered on a stream of futures. But compiler complains about variable fetcher4 which is an Arc. I would appreciate any help for this problem. Code snippet:

                        some_future_stream_of_strings
                        .map(move |sub| {
                            let fetcher4 = fetcher3_2.clone();
                            match Fetcher::parse_link_to_ip(&sub) {
                                Some(ip) => fetcher4
                                    .ping(ip)
                                    .inspect_err(|err| {
                                        error!("Unreachable sub: {}, err:{}", sub.clone(), err)
                                    })
                                    .map(|ping| ping.ok().map(|p| (sub.clone(), ip, p)))
                                    .boxed(),
                                None => {
                                    warn!("Failed to parse sub: {}", sub);
                                    futures::future::ready(None).boxed()
                                }
                            }
                        })
                        .buffer_unordered(conf.batch_size)

error:

error[E0515]: cannot return value referencing local variable `fetcher4`
  --> src/main.rs:79:29
   |
79 | / ...                   match Fetcher::parse_link_to_ip(&sub) {
80 | | ...                       Some(ip) => fetcher4
   | |                                       -------- `fetcher4` is borrowed here
81 | | ...                           .ping(ip)
82 | | ...                           .inspect_err(|err| {
...  |
91 | | ...                   }
   | |_______________________^ returns a value referencing data owned by the current function

The error sounds like that fetcher4.ping(ip) borrows from fetcher4 but without the concrete function signatures that is hard to tell. But my best guess would be that the return value of ping borrows in some way from fetcher4. Then this gets passed to the map where it is turned from an Option into a Result (I guess) and then put in a tuple which then gets boxed.

So long story short if the return value of ping still borrows from fetcher4 it will be part of the return value of the closure and that is exactly the error, that you cannot return something from a function that borrows from something that got initialized within the function (like fetcher4).

For how to fix it I think we need more information. Is fetcher3_2 a reference or moved in owned? Why do you create let fetcher4 = fetcher3_2.clone(); in the first place and not just use fetcher3_2?

thanks for reply. Here is signature of fetcher:

    async fn ping(&self, ip: IpAddr) -> Result<u32, ping_mod::Error>

fetcher3_2 is an Arc<Fetcher> which is declared above this code

                let fetcher3 = fetcher2.clone();
                let fetcher3_2 = fetcher2.clone();
                let dao3 = dao2.clone();
                let sub_groups = conf.sub_groups.clone();
                async move {
                    let par_stream = stream::iter(sub_groups)
                        .then(|group| {
                         ...
                        })
                        .map(move |sub| {
                            let fetcher4 = fetcher3_2.clone();
                            match Fetcher::parse_link_to_ip(&sub) {
                                Some(ip) => fetcher4
                                    .ping(ip)
                                    .inspect_err(|err| {
                                        error!("Unreachable sub: {}, err:{}", sub.clone(), err)
                                    })
                                    .map(|ping| ping.ok().map(|p| (sub.clone(), ip, p)))
                                    .boxed(),
                                None => {
                                    warn!("Failed to parse sub: {}", sub);
                                    futures::future::ready(None).boxed()
                                }
                            }
                        })
                        .buffer_unordered(conf.batch_size)
                       


The futures returned from async fn always capture all the input lifetimes (and other generics). You may be able to avoid that with something like

fn ping(
    &self, ip: IpAddr
) 
-> impl use<> + Future<Output = Result<u32, ping_mod::Error>> {
    // Do whatever you need to using `&self` directly -- maybe clone some
    // `Arc`s or whatever -- then
    async move {
        // Do the rest in here
    }
}

(The default notional desugaring would have use<'_>.)

Or maybe making a async fn ping_arc(self: Arc<Self>, ..) is more straightforward in this case, hard to know.