Reputation: 1451
Consider the following:
struct Str<'a> {
s: &'a str,
}
fn f1<'a>(_: &'a mut Str<'a>) {}
fn f2<'a, 'b>(_: &'a mut Str<'b>) {}
fn main() {
let s = "hello".to_string();
let mut a = Str {
s: &s,
};
f1(&mut a);
// f2(&mut a);
let t: &Str = &a;
}
f2
uses two different lifetimes, as it would when I elided them, which works fine.
At this point, I thought that the lifetime 'a
refers to the lifetime of &mut a
, and 'b
refers to the lifetime of &s
.
And then I wrote f1
which uses a single lifetime parameter, suspecting that lifetime 'a
would refer to the shorter of the lifetime of &mut a
and the lifetime of &s
.
However, this f1
fails with the following error:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:21:19
|
18 | f1(&mut a);
| ------ mutable borrow occurs here
...
21 | let t: &Str = &a;
| ^^
| |
| immutable borrow occurs here
| mutable borrow later used here
The error confuses me: Why is a
still borrowed as mutable after calling f1
?
Why does this fail, and what does the error message supposed to mean?
Upvotes: 3
Views: 294
Reputation: 58785
Why is
a
still borrowed as mutable after callingf1
?
fn main() {
// scope of s ---\
let s = "hello".to_string(); // |
let mut a = Str { // |
s: &s, // |
}; // |
// |
// f1 borrows a until ---\ |
f1(&mut a); // | |
// but it's used here \ | |
let t: &Str = &a; // X // | |
// X X
}
The scope of s
is until the end of main
. Due to the lifetime annotations on f1
's arguments, the mutable reference &mut a
has its lifetime tied to the scope of s
, which means that f1
is borrowing a
for the entire scope of s
.
This is not a problem with immutable references because longer lifetimes may be coerced to shorter ones; in other words lifetimes of immutable references are covariant. But lifetimes of mutable references are invariant. That means they cannot be coerced to shorter (or longer) lifetimes.
Upvotes: 2