1

I'm wondering if someone can help me understand why this program behaves as it does:

fn main() { 
    let mut x = 456; 
    { 
        let mut y = Box::new(&x); 
        y = Box::new(&mut y); 
        println!("GOT {}",*y);
    } 
}

This program compiles under rust 1.35.0 (both 2015 and 2018 editions), and prints

GOT 456

But, I'm confused what's going on here. I'm guessing that this is an example of an auto-dereference. So, in reality, it looks like this:

fn main() { 
    let mut x = 456; 
    { 
        let mut y = Box::new(&x); 
        y = Box::new(&mut *y); 
        println!("GOT {}",*y);
    } 
}

Is that it?

E_net4
  • 27,810
  • 13
  • 101
  • 139
redjamjar
  • 535
  • 2
  • 11

1 Answers1

4

This is a case of deref coercion, but one that is obfuscated by a few other unnecessary parts of the code. The following improvements should be made here:

  1. The mut modifier on variable x is not needed because it is never modified.
  2. The borrow of y in Box::new(&mut y) does not have to be mutable because the variable holds an immutable reference.
  3. The println! implementation also knows to print values behind references, so the explicit * is not needed.

Then, we get the following code:

fn main() { 
    let x = 456; 
    { 
        let mut y = Box::new(&x); 
        y = Box::new(&y); 
        println!("GOT {}", y);
    } 
}

y is a variable of type Box<&i32> which is initially bound to a box created in the outer scope. The subsequent assignment to a new box works because the &y, of type &Box<&i32>, is coerced to &&i32, which can then be put in the box by automatically dereferencing the first borrow. This coercion is required because the variable x can only be assigned values of the same Box<&i32> type.

The lifetime of the reference inside both boxes also ended up being the same, because they refer to the same value in x.

See also:

E_net4
  • 27,810
  • 13
  • 101
  • 139