Unconstrained lifetime parameter for impl

I checked Rust Book and found they never discussed this error in examples. Moreover, they never talked about implementing lifetimes with associated types at the same time.

I'm beginner and I feel lost. I want to return 'Pixel' from iterator for Canvas with mutable reference to 'next' pixel.

This is my current code, and it does not work with 'unconstrained lifetime parameter'. I have no idea where and what to read. Please, help.

My code:

struct Pixel<'img> {
    value: &'img mut u32,
    i: usize,
}

struct Canvas {
    img: Vec<u32>,
    i: usize,
    max_i: usize
}

impl<'a> Iterator for Canvas {
    type Item=Pixel<'a>;
    fn next(&'a mut self) -> Pixel<'a>{
        if self.i >= self.max_i{
            return None
        }
        let retval = Pixel{value: &mut self.img[self.i], i: self.i};
        self.i+=1;
        Some(retval)
    }
}

fn main(){
    let mut canvas = Canvas{img:vec![0;9], i: 0, max_i:3};
    for pixel in canvas {
        * pixel.value = 3 as u32;
    }
}

This is something you can't do in Rust yet, what you are trying to make is a streaming iterator, but this can't be done without generic associated types (GAT). The closet alternative is to use the streaming iterator crate

https://crates.io/crates/streaming-iterator

1 Like

As KrishnaSannasi said, this is the GATs problem.

To dig in a little more: How long does 'a live? What you want to express is that Pixel<'a> lives no longer than &'a mut self, but that relationship would have to be in the trait definition (because it would have to be provably true about all impls of the trait), and it isn't there. It can't be there, because right now it is not possible to use type parameters in associated types (they cannot be generic). And, recall that lifetime parameters are type parameters.

See also this SO answer.

2 Likes

Just so you know, in your case you can circumvent your issue by using functional style:

#![deny(elided_lifetimes_in_paths)]

struct Pixel<'img> {
    value: &'img mut u32,
    i: usize,
}

struct Canvas {
    imgs: Vec<u32>,
    max_i: usize,
}

impl Canvas {
    pub
    fn iter_mut<'iter> (
        self: &'iter mut Self,
    ) -> impl Iterator<Item = Pixel<'iter>>
    {
        self.imgs[.. self.max_i]
            .iter_mut()
            .enumerate()
            .map(|(i, value)| Pixel { value, i })
    }
}

fn main ()
{
    let mut canvas = Canvas {
        imgs: vec![0; 9],
        max_i: 3,
    };
    for pixel in canvas.iter_mut() {
        *pixel.value = 3;
    }
}
2 Likes

Thank you everyone for answers. I really appreciate the help I got. The lifetimes logic with traits on types is still to hard for me, but I'll try harder.

1 Like

Keep at it, lifetimes are hard and will take some time to understand!

1 Like

@Yandros, I'm trying to study your code, but I can't find any documentation for elided_lifetimes_in_paths. Can you point me to documentation for it? The name itself is somewhat self-explanatory (elided lifetimes) but I can't understand what is 'path' here.

I've answered in another thread, since it is a little bit off-topic here and my answer has ended up a little bit longer than expected :sweat_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.