2

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<'_>
jyn
  • 463
  • 4
  • 16
  • 2
    Related: [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132) [Is there an owned version of String::chars?](https://stackoverflow.com/q/47193584) – Sven Marnach May 09 '19 at 19:50
  • Another one: [How can I store a Chars iterator in the same struct as the String it is iterating on?](https://stackoverflow.com/q/43952104) – Sven Marnach May 09 '19 at 19:54
  • https://stackoverflow.com/a/47193986/7669110 did it! If I turned `buf.chars()` into `buf.chars().collect::>().into_iter()` then it works fine – jyn May 09 '19 at 21:09

0 Answers0