(Replying to the OP)
You can never get a &'long mut
by going through a &'short mut &'long mut
.
In your OP, you need to modify a value (a &'b mut dyn A
) you don't have ownership of. You're doing the modification in your function body, so any brief outer borrow will do:
// Equivalent to your original signature
fn test<'b>(c: &mut &'b mut dyn A, d: &mut &'b mut dyn A) {
But as you said, in addition to the borrowing rules, you can't move the &'b mut dyn A
from d
and leave nothing in its place . However, everything is fine if you have something of the same type you can leave in its place. As it happens, you have such a thing: The &'b mut dyn A
from c
that you're trying to overwrite.
fn test<'b>(c: &mut &'b mut dyn A, d: &mut &'b mut dyn A) {
std::mem::swap(c, d)
}
Playground.
If you try to "manually" swap using a temporary, you'll find that the borrow checker still doesn't allow it. swap
and take
and friends are particularly useful when you need to manipulate lifetime-carrying values that are underneath a shorter-lived outside &mut
like we have here. They encapsulate the unsafe
needed to temporarily create the invalid value and then replace it with a valid one -- to manipulate the underlying values without being limited by the outer lifetime.
(Skimming the rest of the thread)
You can't turn a &'short mut &'long mut
into a &'short mut &'short mut
either. Lifetimes behind &'a mut
are invariant -- they can't change at all. If they could, consider:
fn oops<'a>(v: &'a mut Vec<&'static str>) {
let local = "drops at end of function".to_string();
v.push(&*local);
}
fn main() {
let mut v = vec![];
oops(&mut v);
println!("{}", v[0]);
}
If you have a &'a mut Thing<'a>
, you can only use Thing<'a>
through the &'a mut
ever again. The inner borrow becomes only usable through the outer borrow.
This does compile to the point of being to call test
:
fn test<'b>(c: &'b mut &'b mut dyn A, d: &'b mut &'b mut dyn A) {
*c = *d
}
But the error is because you can never use c
and d
again, except through the outer &mut &mut
s which you created -- which you created and then gave away to test
(they are not Copy
). If you're going to use c
and d
again, it can only be indirectly now, via test
giving you some sort of access back by way of those outer borrows:
fn test<'b>(c: &'b mut &'b mut dyn A, d: &'b mut &'b mut dyn A) -> &'b mut dyn A {
*c = *d;
*c
}
Playground.
And so then this one works...
fn test<'b>(c: &mut &'b mut dyn A, d: &'b mut &'b mut dyn A) {
*c = *d;
}
...because
- You can get a
&'b mut dyn A
from a &'b mut &'b mut dyn A
- It's okay to invalidate
d
here by moving from underneath the reference precisely because you can never use it again
- You can't even use
d
inside test
again, because you had to reborrow it for the duration of its entire lifetime to pull the inner &'b mut dyn A
out
- You only borrowed
c
for a shorter period, so now it's ok to use c
after the call to test