1

this is error:

struct A(i32);

fn main(){
    let a = A(1);
    let ra = &a;
    let x = *ra;
}

but this is ok(only change & to Box::new):

struct A(i32);

fn main(){
    let a = A(1);
    let ra = Box::new(a);
    let x = *ra;
    // (1)
}

what is happenning here?

when I add this at (1):

let ra2 = ra;

it say "use of moved value: ra". But I just move the *ra. if in seconed code it moves ra, then in first code why it doesn't move ra?

I write my box(via The Rust Programming Language 15.2), but it also cannot moves ra, and report an error:

use std::ops::Deref;
struct A(i32);

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

fn main(){
    let a = A(1);
    let ra = MyBox::new(a);
    let x = *ra;
}
yymmyb
  • 45
  • 6
  • There are borrow-checker errors in both of the code snippets after adding the `ra2` line. What makes you think one of them works? – Silvio Mayolo Apr 07 '21 at 02:23
  • 1
    `Box` is extra special. See [How do I get an owned value out of a `Box`?](/q/42264041/3650362) and [Dereferencing Box gives back value instead of reference](/q/33653946/3650362) – trent Apr 07 '21 at 02:30
  • 1
    Elaborating on @trentcl's comment: `Box` is considered a built-in reference/pointer type, equally as much as `&T` and `&mut T`. That rarely matters, but this is one of those rare cases. The dereference operator creates a "place expression" for built-in references/pointers, but for everything else (including "smart pointers" like `MyBox`), it acts as `*Deref::deref(&ra)`, so in this case `*&ra.0`, hence the error. If it seems like that doesn't make sense, it's because it *doesn't* really make sense. It's just a quirk of Rust. – Coder-256 Apr 07 '21 at 03:03
  • @Coder-256 `*Deref::deref(&ra)` is still a place expression, just one that can't be moved out of. `&T` and `&mut T` are special, too, in that they don't have to go through `Deref` and `DerefMut`, but the fact that `Box` can be destructively moved out of with `*` is mostly orthogonal to that, and what makes it *extra* special. /nitpick – trent Apr 07 '21 at 13:43

1 Answers1

1

In your first example what happened:

struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a` variable
    let ra = &a; // `ra` references to `a`. 
    println!("{}", a.0); // `a` itself is still exists here and you can read it
    let x = *ra; // A(1) is being tried to be moved from `a`. Error here
    let x = a; // but you can move value from `a` directly. It's ok here.
    // `a` does not exist any more
    // println!("{}", a.0); // error here 
}

In the line let x = *ra; you are trying to "extract" value from behind the reference. But ra does not own the value. It owned by a. So you can't move value from variable, if this variable does not own it.

In your second example different thing happened.

struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a`
    let ra = Box::new(a); // value `A(1)` is moved from `a` to boxed.
    // you can't access to `a` now:
    // println!("{}", a.0); // error here
    let x = *ra; // here you are trying to move value from the memory location where `Box` points to.
    // `ra` does not exist any more!
    // println!("{}", ra.0); // error here. Used of moved value
}

Box owns A(1). As long as there is no references to A(1) you can move value behind the Box.

If you will try to get reference to the value behind the Box, then you also can't move by dereferencing:

struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a`
    let ra = Box::new(a); // value `A(1)` is moved from `a` to box.
    let ra_ref = &ra;
    // both `ra_ref` and `ra` are accesseble here
    
    // let x = *ra; // here you are trying to move value from the memory location where `Box` points to. Error as long as there `ra_ref`
    println!("{}", ra_ref.0);
}
Dmitry
  • 1,092
  • 2
  • 8