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>>,
}

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?

This is not even necessarily true, because (AFAICT) your type A<'a, T> is covariant in 'a, so a shorter borrow &'short self of type &'short A<'a, T> can be (often implicitly) converted into &'short A<'short, T>.

In general, the easiest solution to avoid the problem of “borrowing a type for its entire existence” – particularly important in cases where the types involved are not covariant – would be as follows: couple the returned Iter lifetime to &self but make it a different lifetime from the 'a used in the type. E.g.

pub fn iter<'b>(&'b self) -> Iter<'_b T>

or equivalently

pub fn iter(&self) -> Iter<'_, T>

You can also – if you want to be more “precise”– change Iter so it has two lifetime arguments

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

then you can do something like

pub fn iter<'b>(&'b self) -> Iter<'b, 'a, T>

or equivalently

pub fn iter(&self) -> Iter<'_, 'a, T>

AFAIK, they're not equivalent, since in second case 'b is unbounded.

1 Like

Oops, sorry, a typo (fixed now, thanks for spotting this); in the second case 'b was not even in scope :wink:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.