tl;dr given pub fn func(&'a mut self)
, why is self
considered "mutably borrowed" after func
has run?
Given the following minimal viable example (playground)
pub struct Struct1<'a> {
var: &'a u8,
}
impl<'a> Struct1<'a> {
pub fn new() -> Struct1<'a> {
return Struct1 {
var: &33,
}
}
pub fn func(&'a mut self) -> () {
()
}
}
fn main() {
let mut s1 = Struct1::new();
s1.func(); // point 1
// point 2
s1.func(); // point 3
}
results in compiler error
error[E0499]: cannot borrow `s1` as mutable more than once at a time
--> src/test12-borrow-mut-struct-twice-okay.rs:20:5
|
18 | s1.func(); // point 1
| -- first mutable borrow occurs here
19 | // point 2
20 | s1.func(); // point 3
| ^^
| |
| second mutable borrow occurs here
| first borrow later used here
However, at // point 2
the s1
appears to me to not be anymore borrowed. The func
is done running. What could be still be borrowing self
within func
!? It appears func
at //point 1
has relinquished control of s1
.
What is still borrowing s1
at // point 3
?
Similar questions:
What is still borrowing s1 at // point 3 ?
You're telling the compiler that it's still borrowed, so it's trusting you: while the compiler verifies that your lifetimes are not too short, it doesn't really care if they're so long they make things unusable.
When you write &'a mut self
, the 'a
is the one declared on the impl
block, and thus the one defined on the struct. &'a mut self
literally desugars to:
self: &'a mut Struct1<'a>
so once you've called func()
the rust compiler goes "well this is borrowed for 'a
which is the lifetime associated with s1
which is 'static
, so this is mutably borrowed forever, good day", and thus you get "locked out" of the structure.
In fact you can see this aliasing by trying to explicitly declare an 'a
on func
:
pub fn func<'a>(&'a mut self) -> () {
()
}
error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
--> src/main.rs:11:17
|
5 | impl<'a> Struct1<'a> {
| -- first declared here
...
11 | pub fn func<'a>(&'a mut self) -> () {
| ^^ lifetime `'a` already in scope
error: aborting due to previous error
So rust is telling you in no uncertain term that within the block 'a
always refers to the lifetime declared on the impl
block.
The solution is to just remove the 'a
, that's the wrong lifetime entirely:
pub fn func(&mut self) -> () {
()
}
In that case rustc will automatically introduce a lifetime, and since the function is not actually borrowing anything that lifetime will only extend to the function call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With