The following program is currently rejected by rustc:
fn main() {
let mut x = Box::new(0); let mut y = Box::new(&mut x); y = Box::new(*y);
}
This programs seems to me like it should be fine, since the borrow &mut x is simply moved into the new box. I'm wondering whether there is any specific reason this is not allowed?
fn main() {
let mut x = Box::new(0);
let mut y = Box::new(&mut x);
y = Box::new(*{y});
}
I suspect the reason this happens is reborrowing. The above snippet prevents this by explicitly moving from y (via a block).
In effect, I believe the compiler is rewriting your code to
fn main() {
let mut x = Box::new(0);
let mut y = Box::new(&mut x);
y = Box::new(&mut **y);
}
This is what allows you to do things such as e.g. pass a &mut _ variable to a function even though &mut _ is not Copy; the compiler reborrows the mutable borrow and gives the function a new borrow with a shorter lifetime borrowed from yours. (That's a lot of "borrow"...)
(This question may be a better fit on users than internals, as it has nothing to do with development of the language.)
Ok, that does make some sense. Basically, it reborrows when it shouldn't. Yes, I've heard of that happening before! Interesting that *{y} forces a move.
Interesting stuff.. while exploring this kind of behavior I noticed that I can assign a reborrow of a mut reference to itself, which doesn’t make sense to me either. What kind of rule is behind this and could it be extended to make the original Box example work without the block?
fn foo(_: &mut Box<i32>) {}
// me trying lots of stuff:
pub fn main() {
let mut x = Box::new(0);
// --------------------------
let mut y: Box<&mut Box<i32>> = Box::new(&mut x);
// y = Box::new(*y); // doesn’t work
y = Box::new(*{y}); // but this does
foo(*y); // advantage: *y doesn’t move anything
foo(*y);
// --------------------------
let mut z = &mut x;
z = z; // compiler figures not to reborrow, so that it’s okay?
foo(z); // doesn’t move anything, because it IS (implicitly) a reborrow
foo(z);
// --------------------------
let mut y1: &mut &mut Box<i32> = &mut &mut x;
y1 = &mut *y1; // explicit reborrow; why does this work??
// (similarly above, z = &mut *z would’ve worked...)
foo(*y1);
foo(*y1);
}