What's the reason cause below codes can not compile?

fn main() {

    #[derive(Debug)]
    struct Node {
        next_node: Option<*const Node>,
        // _marker: PhantomData<Node>
    }

    let node1 = Node {
        next_node: None,
        // _marker: PhantomData
    };

    let node2 = Node {
        next_node: Some(&node1 as *const Node),
        // _marker: PhantomData
    };
    let p = node2.next_node.unwrap();
    println!("{:#?}",  unsafe { *p });
}

and if I change to

    println!("{:#?}",  unsafe { &*p });

it will work.
can somebody explain it to me?

Well I guess it's because of println macro, but I am not sure what exactly it does.

The println! macro has nothing to do with the error, which is

error[E0507]: cannot move out of `*p` which is behind a raw pointer
  --> src/main.rs:19:33
   |
19 |     println!("{:#?}",  unsafe { *p });
   |                                 ^^ move occurs because `*p` has type `Node`, which does not implement the `Copy` trait

Pointers do not implement Copy, so you'd be unable to derive Copy for Node. You would have to explicitly .clone() it, which would necessitate #[derive(Clone)]. Note that unless you know what you're doing, it is extremely likely that you will cause undefined behavior when dereferencing raw pointers and using unsafe. If you would like more assistance, the purpose behind your code is important and was not noted.

2 Likes

Thanks for explaining it to me, I am doing some exercising on unsafe rust, not for any production uses, thank you again for the warning.

1 Like

The reason Rust attempts to move the value *p is that it's in a block. If you had written unsafe { println!("{:#?}", *p) }; it would work, because println! automatically takes all of its arguments as references. But the unsafe block interferes with that by forcing its value to be owned.

1 Like

This doesn't seems right:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=046934a01751ed0d5b1b8b3ce32f3630

1 Like

I guess what @jhpratt wanted to say is that you can't copy out from the pointer using the deref operator. To read the pointed value you should use the std::ptr::read() function.

1 Like

I did not interpreted it like that, @jhpratt said you can't derive Copy for the Node type because raw pointers are not Copy, but you can. Basically, this works:

fn main() {

    #[derive(Clone, Copy, Debug)]
    struct Node {
        next_node: Option<*const Node>,
        // _marker: PhantomData<Node>
    }

    let node1 = Node {
        next_node: None,
        // _marker: PhantomData
    };

    let node2 = Node {
        next_node: Some(&node1 as *const Node),
        // _marker: PhantomData
    };
    let p = node2.next_node.unwrap();
    println!("{:#?}",  unsafe { *p });
}