As the title states, why does the following code compile?
use std::ops::Deref;
struct Foo {}
fn main() {
let b = Box::new(Foo{});
let pb = *b; //works
// let pb = *b.deref(); // error[E0507]: cannot move out of a shared reference
}
The same does not hold true for a custom type with non-Copy target.
use std::ops::Deref;
struct Foo<T> {
p: T,
}
impl<T> Deref for Foo<T> {
type Target = T;
fn deref(&self) -> &<Self as Deref>::Target {
&self.p
}
}
fn main() {
let f = Foo { p: vec![1u8] };
let pf = *f; // error[E0507]: cannot move out of a shared reference
let pf = *f.deref(); // error[E0507]: cannot move out of a shared reference
}
Is *Box
not doing *Box.deref()
?
Is
*Box
not doing*Box.deref()
?
No, it is not. This is one of those cases of compiler magic -- the Box
type is a bit special and the compiler treats it specially.
Looking at the Deref
implementation for Box
gives us a very strong hint that something is different:
fn deref(&self) -> &T {
&**self
}
If this were any other type, this would cause infinite recursion, but the deref operator (*
) is handled internally be the compiler when applied to a Box
value.
One of the special things you're allowed to do with boxes is move its contained value out, which has the side-effect of destroying the box and freeing its heap allocation.
(Also, the unstable Box::into_inner()
associated function takes boxed: Self
and simply returns *boxed
, further illustrating this.)