Hubro
Hubro

Reputation: 59323

Why do I need to provide a lifetime parameter for my iterator item?

I'm trying to make a simple log parser as my first project in Rust.

I've made a struct to contain each parsed log line and I'm now making a "parser" struct that should own the BufReader and implement Iterator to let the user iterate over each parsed line.

As soon as I start implementing Iterator I'm hitting a snag.

Part of implementing Iterator is to set an associated type, and I'm not allowed to set the associated type to be LogLine:

error[E0106]: missing lifetime specifier
  --> src/parser.rs:27:17
   |
27 |     type Item = LogLine;
   |                 ^^^^^^^ expected named lifetime parameter
   |
help: consider introducing a named lifetime parameter
   |
27 |     type Item<'a> = LogLine<'a>;
   |              ++++   ~~~~~~~~~~~

For more information about this error, try `rustc --explain E0106`.

Why do I have to specify a lifetime parameter for LogLine? From what I understand, all I've said in the definition of LogLine is that each string slice field has to live as long as the struct itself.

Why does that make it necessary to provide a named lifetime parameter in this situation, and what do I set it to?


This is my code:

use std::fs::File;
use std::io;
use std::io::BufReader;

pub struct LogParser {
    pub bufreader: BufReader<File>,
}

pub struct LogLine<'a> {
    line: String,
    severity: &'a str,
    message: &'a str,
}

impl LogParser {
    pub fn new(path: &str) -> io::Result<Self> {
        let file = File::open(path)?;
        let bufreader = BufReader::new(file);

        return Ok(LogParser {
            bufreader: bufreader,
        });
    }
}

impl Iterator for LogParser {
    type Item = LogLine;

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

Unrelated to the question, this is my plan:

I'm hoping this is sound.

Upvotes: 0

Views: 400

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 70900

From what I understand, all I've said in the definition of LogLine is that each string slice field has to live as long as the struct itself.

This is false: the meaning of having a lifetime parameter on the struct is that the struct is generic over this lifetime parameter, and you have to provide some lifetime to create an actual type. This lifetime will serve as the lifetime of the &str fields. It is true that this lifetime has to be smaller than that of the instance, but this is because of another thing (well-formedness).

What you're trying to do is problematic: you're trying to create a self-referential struct, i.e. a struct that contain a reference to its own field. You cannot do that easily. See Why can't I store a value and a reference to that value in the same struct? for problem explanation and solutions, but the TL;DR is "don't do that".

Upvotes: 1

Related Questions