pointersrustreferencedereferencesyntactic-sugar

Moving value out of the Box by dereferencing (and what it is desugared into)?


Consider the following code:

    let x = String::from("123");

    let bx = Box::new(x);

    let dbx = *bx;

    println!("{}", dbx);
    //println!("{}", bx); // error due to ownership move

Here x is created, later boxed into bx, and later bx is somehow unboxed in expression *bx.

As far as I understand, ownership of data is moved from x to bx to dbx, and data itself (at least memory occupied by struct String) is copied from stack (x) to heap (pointed by bx) to stack (dbx).

My main question is: how does compiler interpret *bx?

It does not look like Deref for Box, since this would imply claiming ownersip of value, having reference to value (&String).

It looks like compiler somehow desugars this to into_inner, but it is not obvious to me why.

So, What is going on here?

Bonus question: is there a way to see how code gets desugared, or how do I approach demystifying rust magic in general. Auto dereferencing involving various smart pointers is of particular interest to me now. I tried cargo-inspect but it does not seem to be helpful here.


Solution

  • Normally you are right that * goes through Deref or DerefMut and only has access to &T or &mut T. However, Box gets special treatment and is allowed by the compiler to move out of a dereference.

    There is currently no trait that allows one to do that for user-defined types (a DerefMove trait has been proposed but nothing accepted AFAIK). So there is no "desugaring" to be done; just *bx is what you see and what is left is handled by the compiler internally. It really is "magic" in this case.

    You can see that it doesn't desugar to into_inner because the current implementation of that is to use * (source):

    pub fn into_inner(boxed: Self) -> T {
        *boxed
    }
    

    See also: