I want to create a chain of iterators, so that all IO is lazy. However, when I try to create an iterator in a struct based on some underlying data, I get an error saying 'lifetime cannot outlive method body'.
I thought of storing the original buffer in the struct as well so the lifetimes match, but that gives me the same error. I looked at https://stackoverflow.com/a/27163349/7669110 for a while, but it doesn't compile with rustc 2018. What am I doing wrong? How can I generate an iterator in a struct from some underlying data?
The strange thing is if I used a single iterator and don't generate it, it works fine:
use std::str::Chars;
fn main() {
println!("{}", IterContainer { iter: "blah".chars() }.next());
}
struct IterContainer<'a> {
iter: Chars<'a>
}
impl<'a> IterContainer<'a> {
fn next(&mut self) -> Option<char> {
self.iter.next()
}
}
Here's the smallest sample that still has the issue:
use std::io::{self, BufRead, BufReader, Read};
use std::str::Chars;
fn main() {
println!("{}", IterContainer {
reader: BufReader::new(io::stdin()),
buf: String::new(),
iter: "".chars()
}.next().unwrap());
}
struct IterContainer<'a, R: Read> {
reader: BufReader<R>,
buf: String,
iter: Chars<'a>
}
impl<'a, R: Read> IterContainer<'a, R> {
fn next(&mut self) -> Option<char> {
match self.iter.next() {
Some(c) => Some(c),
None => {
self.reader.read_line(&mut self.buf);
self.iter = self.buf.chars();
self.iter.next()
}
}
}
}
I tried something similar but with Lines
instead of BufReader
and I got similar errors.
I expect this to compile and print "b", but instead it fails with a lot of errors:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> tmp2.rs:24:38
|
24 | self.iter = self.buf.chars();
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 19:5...
--> tmp2.rs:19:5
|
19 | / fn next(&mut self) -> Option<char> {
20 | | match self.iter.next() {
21 | | Some(c) => Some(c),
22 | | None => {
... |
27 | | }
28 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> tmp2.rs:24:29
|
24 | self.iter = self.buf.chars();
| ^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 18:6...
--> tmp2.rs:18:6
|
18 | impl<'a, R: Read> IterContainer<'a, R> {
| ^^
= note: ...so that the expression is assignable:
expected std::str::Chars<'a>
found std::str::Chars<'_>