#[test]
fn test_lifetime() {
struct Aa<'a> {
_1: PhantomData<&'a ()>,
}
fn f<'a>(_b: &'a mut Aa<'a>) {}
let mut v = Aa {
_1: PhantomData::default(),
};
f(&mut v);
let c = &v;
}
IMO, the mutable reference seems should be dropped as soon as function f is finished, but it returns an error as:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/lifetime.rs:16:13
|
14 | f(&mut v);
| ------ mutable borrow occurs here
15 |
16 | let c = &v;
| ^^
| |
| immutable borrow occurs here
| mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
warning: `play` (bin "play" test) generated 7 warnings
error: could not compile `play` due to previous error; 7 warnings emitted
I can not really understand why &v will be used as a mutable borrow either.
This is a bad anti-pattern in Rust. A mutable reference &'a mut … to a type that has the same lifetime 'a as a parameter will always have the effect that the value is borrowed for its entire existence, and thus you can do nothing at all with the value v after calling f(&mut v) (besides implicitly dropping it).
A shared reference &'a … to a type that has the same lifetime 'a as a parameter (i.e. something like &'a A<'a>) will sometimes be problematic, too, if that type (Aa<'a>) is invariant in the lifetime 'a.
The reason why the error message reads like that is because the &v constitutes a usage of v, and any usage of v requires the lifetime 'a in its type Aa<'a> to be still “alive”.
Since the previous call f(&mut v) ensured that the mutable borrow of v happens (at least) as long as the lifetime 'a (because of the type &'a mut Aa<'a> which says that the mutable borrow lasts for (at least) the lifetime 'a), the compiler will consequently consider the usage of v in &v to keep the mutable borrow alive, and report it, perhaps somewhat unintuitively, as “mutable borrow […] used here”.
So the lifetime of &'a mut is actually reduced to the lifetime of borrow inside Aa itself, thus I can never release the mutable borrow until it's dropped. Is that correct?
In fact, there should be two different lifetime annotations here, but I was thinking about reusing one of them. It seems I have to introduce a new lifetime to fix this issue.