ZyS
ZyS

Reputation: 111

What's the difference between `*` operator and `deref()` method?

What I've been told is that once an object (in this cast sth) implements the Drop trait then it can use * operator to call its deref() method. So I think the result of using * should be the same as the result of explicitly call deref(). But I find in some cases the two results are not equal. For example:

use std::ops::Deref;

fn main() {
    let sth = Box::new(5);
    println!("{:p}", sth.deref());
    println!{"{:?}", *sth};
}

I searched the docs and know that the signature of deref() of Box is (&self)->&T. That means it should return a reference of inner value. However, *sth looks like it is returning the inner value directly. Why are the two results not equal?

Upvotes: 4

Views: 1667

Answers (2)

Masklinn
Masklinn

Reputation: 42492

As Chayim answered deref() is used to get a reference to the inner item, which the * then actually accesses.

However when it comes to Box you won't find its behaviour regulated by any trait (at least as yet): Box is a language item.

While unlike references it looks like a normal type it really has the same status, and lives at the core of the language itself. As a result, it can (and does) behave in ways no other type can.

One of these behaviours is the ability to move on dereference, which is completely unique to it (RFCs have been proposed for that in the past but AFAIK little progress has been made).

Although in your specific case that's not even involved: println! will always reference its parameters, so

println!{"{:?}", *sth};

really does

let args = Args::new(&*sth);

and then you get the value because there is a blanket impl Display for &T where T: Display which delegates to T's implementation (and the same for Box incidentally).

Which you can check by duplicating the line and seeing that it works fine, which it would not have if the value had been moved (and the box dropped).

Upvotes: 1

Chayim Friedman
Chayim Friedman

Reputation: 71430

* is not the same as v.deref() (or more exactly Deref::deref(&v)) - it's more like *Deref::deref(&v) (note the *).

Regarding Box specifically, it can move out of it, like:

let s = Box::new(String::new());
let moved_out = *s;
// s; // Error, moved out of the `Box`.

In either type, it creates a place - it can be *Deref::deref(&v) or *DerefMut::deref_mut(&v), depending on whether mutable access is required.

Upvotes: 4

Related Questions