Stream filter and reference lifetime

In the following snippet, is there a way to have the second example compile without the extra allocation (i.e. without str.to_owned()), or can I annotate the closure in some way?

How come filter_map can deal with the reference lifetime here and filter can't?

use futures::prelude::*;

#[tokio::main]
async fn main() {
    let stream = stream::iter(vec!["foo", "bar"]);
    
    // Works fine:
    let stream = stream.filter_map(|str| async move {
        println!("{}", str);
        Some(str)
    });
    
    // Fails with:
    // return type of closure `impl futures::Future` contains a lifetime `'2`
    let stream = stream.filter(|str| {
        //let str = str.to_owned();
        async move {
            println!("{}", str);
            true
        }
    });
    
    stream.collect::<String>().await;
}

Initially stream is a stream of &'static str. filter_map receives the stream items by value, so it gets a &'static str, which doesn't contain any anonymous lifetime. filter however receives a reference to the stream items, so str there is a &'anon &'static str. Moving the reference with the 'anon lifetime inside the async move is what causes the problem. Since &'static str is Copy you can solve this by using .filter(|&str| { /* ... */ } or by putting a let str = *str; instead of theat .to_owned(). Another option would be do the print outside the async move block, thus avoiding to borrow str in the return type.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.