1

I'm trying to encapsulate a CSV iterator into one of my structs like this:

struct PopulationCount {
    city: String,
    country: String,
    count: u64,
}

struct PopulationIter<'a> {
    reader: csv::Reader<std::fs::File>,
    records: DecodedRecords<'a, std::fs::File, Row>,
}

impl<'a> PopulationIter<'a> {
    fn new(file_path: &str, country: &str) -> Result<PopulationIter<'a>, Box<Error>> {
        let file = File::open(file_path)?;
        let mut reader = csv::Reader::from_reader(file);

        let decoded_records = reader.decode::<Row>();

        Ok(PopulationIter {
            reader: reader,
            records: decoded_records,
        })
    }
}

impl<'a> Iterator for PopulationIter<'a> {
    type Item = csv::Result<Row>;

    fn next(&mut self) -> Option<Self::Item> {
        self.records.next()
    }
}

As far as I understand, DecodedRecords holds a reference to the csv::Reader, that's why the csv::Reader must live as long as the DecodedRecords.

Trying to compile this code gives me this error:

error: `reader` does not live long enough
  --> src/main.rs:39:31
   |
39 |         let decoded_records = reader.decode::<Row>();
   |                               ^^^^^^ does not live long enough
...
42 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the block at 34:85...
  --> src/main.rs:34:86
   |
34 |     fn new(file_path: &str, country: &str) -> Result<PopulationIter<'a>, Box<Error>> {
   |                                                                                      ^

I don't understand this since the reader is passed to the PopulationIter struct, I would think move semantics would apply, making reader live as long as the struct. This is obviously not what happens here.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Momh
  • 732
  • 5
  • 17
  • 1
    Is is possible to include a [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve) example that reproduces your problem? – wimh Dec 08 '16 at 16:40
  • Related: [variable does not live long enough when storing a csv::DecodedRecords iterator](http://stackoverflow.com/q/36645452/155423) – Shepmaster Dec 08 '16 at 16:51
  • *I would think move semantics would apply, making `reader` live as long as the struct* — kind of "yes", kind of "no". Lifetimes mark how long a value lives **at the current address**. When you move `reader`, you invalidate any references to it because those references contain the address of the value, which just changed. – Shepmaster Dec 08 '16 at 16:54
  • Note that your function has a warning sign in it: `fn new(file_path: &str, country: &str) -> Result, Box>` - it returns a lifetime *chosen by the caller* that isn't constrained by any input lifetimes. See also [Is there any way to return a reference to a variable created in a function?](http://stackoverflow.com/q/32682876/155423) – Shepmaster Dec 08 '16 at 16:55

0 Answers0