I'm struggling to get an element from a Vec
that is a reference with a lifetime. I've simplified my code down to this:
pub trait Runnable {}
pub struct RunList<'a> {
runnables: Vec<&'a mut Runnable>,
}
impl<'a> RunList<'a> {
pub fn get(&self, id: usize) -> &'a mut Runnable {
self.runnables[id]
}
}
fn main() {}
which produces this error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:9:9
|
9 | self.runnables[id]
| ^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
--> src/main.rs:8:5
|
8 | / pub fn get(&self, id: usize) -> &'a mut Runnable {
9 | | self.runnables[id]
10| | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:9:9
|
9 | self.runnables[id]
| ^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 7:1...
--> src/main.rs:7:1
|
7 | impl<'a> RunList<'a> {
| ^^^^^^^^^^^^^^^^^^^^
= note: ...so that the expression is assignable:
expected &'a mut Runnable + 'a
found &mut Runnable + 'a
First, remove the lifetime parameter
'a
from the type of the return value ofget
:This gets you to the underlying problem:
self.runnables[id]
borrows&'a mut Runnable
immutably and dereferences it implicitly. You can't move&'a mut Runnable
out of this immutable borrow. Instead, you can mutably reborrow the runnable which requires a mutable borrow ofself
:To understand what's exactly going on here one should read up on: What is the return type of the indexing operation?
is equivalent to:
index
returns an immutable reference to&'a mut Runnable
, which is of type&&mut (Runnable + 'a)
. Returning*r
does not work, because you can't move the mutable reference1 out of the borrowed content and also data in an immutable reference can't be borrowed mutably (&mut**r
does not work). Therefore, you need the version ofindex
which grants mutable access to the indexed element:index_mut
This works, because
*r
actually reborrows theRunnable
inside mutably (&mut**r
). In contrast to the case with the immutable referencer
above, mutably borrowing the data inside the mutable referencer
is perfectly fine. When performing&mut**r
the parameter'a
gets lost in the process of dereferencing. So, returning&'a mut Runnable
instead of&mut Runnable
does not work here.Finally,
&mut *self.runnables[id]
tells the compiler to implicitly resolve to*self.runnables.index_mut(id)
instead of*self.runnables.index(id)
.*&mut self.runnables[id]
would also work.1 Mutable references are not
Copy
. If you changed all&'a mut Runnable
in your code to&'a Runnable
, it would compile, because immutable references areCopy