I have this piece of code:
#[derive(Debug)]
struct Foo<'a> {
x: &'a i32,
}
impl<'a> Foo<'a> {
fn set(&mut self, r: &'a i32) {
self.x = r;
}
}
fn main() {
let v = 5;
let w = 7;
let mut f = Foo { x: &v };
println!("f is {:?}", f);
f.set(&w);
println!("now f is {:?}", f);
}
My understanding is that in the first borrow of the value of v
, the generic lifetime parameter 'a
on the struct declaration is filled in with the lifetime of the value of v
. This means that the resulting Foo
object must not live longer than this 'a
lifetime or that the value of v
must live at least as long as the Foo
object.
In the call to the method set
, the lifetime parameter on the impl
block is used and the lifetime of the value of w
is filled in for 'a
in the method signature. &mut self
is assigned a different lifetime by the compiler, which is the lifetime of f
(the Foo
object). If I switched the order of the bindings of w
and f
in the main
function, this would result in an error.
I wondered what would happen if I annotated the &mut self
reference with the same lifetime parameter 'a
as r
in the set
method:
impl<'a> Foo<'a> {
fn set(&'a mut self, r: &'a i32) {
self.x = r;
}
}
Which results in the following error:
error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable
--> src/main.rs:21:31
|
19 | f.set(&w);
| - mutable borrow occurs here
20 |
21 | println!("now f is {:?}", f);
| ^ immutable borrow occurs here
22 | }
| - mutable borrow ends here
In contrast to the example above, f
is still considered mutably borrowed by the time the second println! is called, so it cannot be borrowed simultaneously as immutable.
How did this come to be?
By not leaving off the lifetime annotation the compiler filled one in for me for &mut self
in the first example. This happens by the rules of lifetime elision. However by explicitly setting it to 'a
in the second example I linked the lifetimes of the value of f
and the value of w
.
Is f
considered borrowed by itself somehow?
And if so, what is the scope of the borrow? Is it min(lifetime of f
, lifetime of w
) -> lifetime of f
?
I assume I haven't fully understood the &mut self
reference in the function call yet. I mean, the function returns, but f
is still considered to be borrowed.
I am trying to fully understand lifetimes. I am primarily looking for corrective feedback on my understanding of the concepts. I am grateful for every bit of advice and further clarification.
In the call to the method
set
the lifetime parameter on the impl block is used and the lifetime of the value ofw
is filled in for'a
in the method signature.
No. The value of the lifetime parameter 'a
is fixed at the creation of the Foo
struct, and will never change as it is part of its type.
In your case, the compiler actually choses for 'a
a value that is compatible with both the lifetimes of v
and w
. If that was not possible, it would fail, such as in this example:
fn main() {
let v = 5;
let mut f = Foo { x: &v };
println!("f is {:?}", f);
let w = 7;
f.set(&w);
println!("now f is {:?}", f);
}
which outputs:
error[E0597]: `w` does not live long enough
--> src/main.rs:21:1
|
18 | f.set(&w);
| - borrow occurs here
...
21 | }
| ^ `w` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
Exactly because the 'a
lifetime imposed by v
is not compatible with the shorter lifetime of w
.
In the second example, by forcing the lifetime of self
to be 'a
as well, you are tying the mutable borrow to the lifetime 'a
as well, and thus the borrow ends when all items of lifetime 'a
goes out of scope, namely v
and w
.
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