2

I have a Vec<Point> with a simple struct Point {x: f32, y: f32, z: f32}. My vector represents hundreds of thousands of lines in 3D (it could be a Vec<Vec<Point>> in fact), so I keep track of the start/end of all lines.

pub struct Streamlines {
    lengths: Vec<usize>,
    offsets: Vec<usize>,  // cumulative sum of lengths
    data: Vec<Point>,
}

I want to create a non-consuming iterator for it, usable like:

for streamline in &streamlines {
    for point in &streamline {
        println!("{} {} {}", point.x, point.y, point.z);
    }
    println!("")
}

I found How to implement Iterator and IntoIterator for a simple struct? and started copyi-err, adapting :)

impl IntoIterator for Streamlines {
    type Item = &[Point];
    type IntoIter = StreamlinesIterator;

    fn into_iter(self) -> Self::IntoIter {
        StreamlinesIterator {
            streamlines: self,
            it_idx: 0
        }
    }
}

struct StreamlinesIterator {
    streamlines: &Streamlines,
    it_idx: usize
}

impl Iterator for StreamlinesIterator {
    type Item = &[Point];

    fn next(&mut self) -> Option<&[Point]> {
        if self.it_idx < self.streamlines.lengths.len() {
            let start = self.streamlines.offsets[self.it_idx];
            self.it_idx += 1;
            let end = self.streamlines.offsets[self.it_idx];

            Some(self.streamlines.data[start..end])
        }
        else {
            None
        }
    }
}

I used slices because I only want to return parts of the vector, then I added lifetimes because it's required, but now I have this error cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements

In fact, I don't actually know what I'm doing with the damn <'a>.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Nil
  • 2,345
  • 1
  • 26
  • 33
  • 2
    The source you're copying from used an iterator struct with a lifetime parameter (`PixelIterator<'a>`). The Book contains a [relevant section](https://doc.rust-lang.org/book/second-edition/ch10-03-lifetime-syntax.html#lifetime-annotations-in-struct-definitions) on using generic lifetime annotations in structs. Can you be more specific about how lifetime parameters are confusing you? – E_net4 Oct 02 '17 at 17:25
  • 1
    Did you read the whole (accepted) answer to the linked question? Shepmaster also included an example of an iterator that doesn't consume the type. Notice that `IntoIterator` is implemented for `&'a Pixel` instead of `Pixel` – trent Oct 02 '17 at 17:35
  • 1
    Please review how to create a [MCVE]. You've said "then I added lifetimes" but you **didn't show us what that meant**. – Shepmaster Oct 02 '17 at 17:45
  • I did read the second book and the accepted answer from the linked question (which was iterating over POD, I'm not). That didn't make me an expert, sadly. My bad for the "verifiable example" though. I didn't add it because I simply added some `<'a>` that looked quite random to me. I was wrong. – Nil Oct 02 '17 at 18:38

1 Answers1

7

cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements

That's because you aren't correctly implementing Iterator and have something like this:

impl<'a> Iterator for StreamlinesIterator<'a> {
    type Item = &'a [Point];

    fn next(&mut self) -> Option<&[Point]> { /* ... */ }

    // ...
}

Due to lifetime inference, this is equivalent to:

impl<'a> Iterator for StreamlinesIterator<'a> {
    type Item = &'a [Point];

    fn next<'b>(&'b mut self) -> Option<&'b [Point]> { /* ... */ }

    // ...
}

This is attempting to return a reference that lives as long as the iterator, which you cannot do.

If you correctly implement Iterator, it works:

impl<'a> Iterator for StreamlinesIterator<'a> {
    type Item = &'a [Point];

    fn next(&mut self) -> Option<&'a [Point]> { /* ... */ }

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

    // ...
}

I don't actually know what I'm doing with the damn <'a>.

You should go back and re-read The Rust Programming Language, second edition. When you have specific questions, Stack Overflow, IRC, the User's Forum will all be waiting.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Right, as you guessed, I forgot the `&'a` in `next` signature. Using `Self::Item` is indeed a good idea to avoid errors. Thank you for your answer. – Nil Oct 02 '17 at 18:45