Rafaelo
Rafaelo

Reputation: 153

When &self has different lifetime than the struct

On this example

use std::marker::PhantomData;

pub struct A<'a, T> {
    elements: Vec<B<'a, T>>
}

pub struct B<'a, T> {
    _phantom: PhantomData<&'a T>
}

impl<'a, T> A<'a, T> {
    pub fn iter(& self) -> Iter<'a, T> {
        Iter {
            iter: self.elements.iter(),
        }
    }
}

pub struct Iter<'a, T> {
    iter: std::slice::Iter<'a, B<'a, T>>,
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e246ef19b9ae5f1d405bde7c59d456d7

I get

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/lib.rs:14:24
   |
14 |             iter: self.elements.iter(),
   |                                 ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/lib.rs:12:17
//...

I know why this happens: the elements in self.elements lives as long as &self, so it cannot possibly create an Iter with lifetime a. The easy solution would be to do

pub fn iter(&'a self) -> Iter<'a, T> {
    Iter {
        iter: self.elements.iter(),
    }
}

but then I'm forced to borrow the &self for its entire existence which leads me to other problems. Whatis the easiest solution here?

Upvotes: 4

Views: 185

Answers (1)

kmdreko
kmdreko

Reputation: 60492

Your Iter implementation is over-constrained; you have two unrelated lifetimes that are required to be the same. You should separate them:

impl<'a, T> A<'a, T> {
    pub fn iter(&self) -> Iter<'a, '_, T> {
        Iter {
            iter: self.elements.iter(),
        }
    }
}

pub struct Iter<'a, 'b, T> {
    iter: std::slice::Iter<'b, B<'a, T>>,
}

That way, even if 'a is invariant, you don't run into issues with linking that lifetime to self. See it working on the playground (with additional tests).

Upvotes: 8

Related Questions