1
struct A;

fn y<'r>(a: &'r mut Vec<&'r A>) {}

fn x<'r>(a: &'r mut Vec<&'r A>) {
    y(a);
    y(a);
}

Compilation of this code fails, saying that *a cannot be mutably borrowed second time. When I make the signature look like this (a: &'a mut Vec<&A>), i.e. remove a lifetime from a reference of Vecs content, it compiles just fine.

Why the original code cannot be compiled? I'm unable to see an issue here. For me lifetimes on reference to vector and its content mean just that vector and its content live for the same amount of "time". Where am I wrong?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
OlegTheCat
  • 4,443
  • 16
  • 24
  • 1
    because you limit the lifetime, by writhing it this way. There is no reason to do that in your exemple. Compiler in 2018 edition give an accurate explanation. – Stargateur Jan 31 '19 at 12:32
  • 2
    Tl;dr the duplicate: Because `&mut T` is invariant in `T`, `y(a)` has to reborrow `a` for all of `'r`. In general, if you don't specify any lifetimes, they will be minimally constrained; if you specify a single lifetime and use it everywhere, they will be maximally constrained. If you get a compiler error, and try to fix it by creating one lifetime and using it everywhere, you're likely to accidentally overconstrain your code, which leads to hard-to-debug errors. Think hard before you use the same lifetime in two different places. – trent Jan 31 '19 at 12:46

1 Answers1

4

In this function:

fn y<'r>(a: &'r mut Vec<&'r A>) {}

you are asking that &A has the same lifetime as the (mutable) reference to the Vec. If the reference wasn't mutable, you'd be asking that the lifetime of the &A outlives the reference to the vector, and there wouldn't be a problem. However, mutability makes lifetimes invariant.

Inside this function:

fn x<'r>(a: &'r mut Vec<&'r A>) {
    y(a);
    y(a);
}

the lifetime of a is the full duration of the function because it's used in every statement. The borrow checker believes (based on the constraint on the lifetimes in y) that y needs the &A for the full lifetime of the vector reference. So the second time you call y, it thinks the reference is still in use.

The reason why removing the explicit lifetimes fixes it is because the borrow checker will infer different lifetimes:

fn y<'r, 's>(a: &'r mut Vec<&'s A>) {}

Now they are not tied together, the borrow checker no longer believes that y needs &A for the whole lifetime of a.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204