Borrowed value does not live long enough for closure


#1

I’m trying to pass a function as the parameter to a map() call for a future, but I keep getting an error that one of my variables does not live long enough.

fn parse_logs(log_chunk: Chunk) -> Box<Stream<Item=RequestMessage, Error=hyper::Error>> {
    let log_str = String::from_utf8(log_chunk.to_vec()).unwrap();

    let req_stream = log_str.lines().map(move |line| { ... });

    Box::new(stream::iter_ok(req_stream.filter(move |m| m.is_some()).map(move |o| o.unwrap())))
}

I get the following error:

error[E0597]: `log_str` does not live long enough
  --> src/http_server.rs:53:9
   |
53 |         log_str.lines().map(move |line| {
   |         ^^^^^^^ borrowed value does not live long enough
...
78 | }
   | - borrowed value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

I believe this is because I’m trying to use it in a future, but have created a temporary variable in a function being passed as a parameter to map() and that requires a static lifetime; but I also could be completely wrong about that :slight_smile:

Any help here would be greatly appreciated!

Full code can be found here: https://github.com/wspeirs/logstore/blob/dd2ad362da04b7f3cc47ed126ce3500f4bdf0aab/src/http_server.rs#L48


#2

The problem is that all the transformations you’re applying are referencing the log_str created in the first line. You’re trying to return an iterator that references that String, but the log_str will be be dropped at the end of the function – hence the error message. The 'static message comes from the fact the Boxes have by default the 'static lifetime.


#3

Easiest way out is to collect() your iterator chain into a Vec and pass the Vec to iter_ok.

Alternatively, you can use a Cursor and a Lines iterator from std::io:

let log_str: String = ...;
let s = Cursor::new(log_str).lines().map(...).filter(...);
Box::new(stream::iter_ok(s))

Note that this iterator yields a String (wrapped inside a Result) so it creates a copy of each line.

Unfortunately, the std::str::Lines iterator, which doesn’t copy but yields slices, cannot be embedded in a struct that holds the String as well - that would create a self referential struct. You may be able to get around this with use of the rental crate, or otherwise your own unsafe code that takes advantage of the fact that String has a stable heap address of its data.


#4

Using collect() did the trick, thanks!