Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the return type of Deref::deref itself a reference?

I was reading the docs for Rust's Deref trait:

pub trait Deref {
    type Target: ?Sized;
    fn deref(&self) -> &Self::Target;
}

The type signature for the deref function seems counter-intuitive to me; why is the return type a reference? If references implement this trait so they can be dereferenced, what effect would this have at all?

The only explanation that I can come up with is that references don't implement Deref, but are considered "primitively dereferenceable". However, how would a polymorphic function which would work for any dereferenceable type, including both Deref<T> and &T, be written then?

like image 700
corazza Avatar asked Jul 25 '15 08:07

corazza


People also ask

What is Deref trait rust?

Trait std::ops::DerefUsed for immutable dereferencing operations, like *v . In addition to being used for explicit dereferencing operations with the (unary) * operator in immutable contexts, Deref is also used implicitly by the compiler in many circumstances. This mechanism is called ' Deref coercion'.

What is Dereferencing in Rust?

The dereference operator is also known as the indirection operator. Simply put, the dereferencing operator allows us to get the value stored in the memory address of a pointer. In Rust, we use the Deref trait to customize the behaviour of the dereferencing operator.


1 Answers

that references don't implement Deref

You can see all the types that implement Deref, and &T is in that list:

impl<'a, T> Deref for &'a T where T: ?Sized

The non-obvious thing is that there is syntactical sugar being applied when you use the * operator with something that implements Deref. Check out this small example:

use std::ops::Deref;

fn main() {
    let s: String = "hello".into();
    let _: () = Deref::deref(&s);
    let _: () = *s;
}
error[E0308]: mismatched types
 --> src/main.rs:5:17
  |
5 |     let _: () = Deref::deref(&s);
  |                 ^^^^^^^^^^^^^^^^ expected (), found &str
  |
  = note: expected type `()`
             found type `&str`

error[E0308]: mismatched types
 --> src/main.rs:6:17
  |
6 |     let _: () = *s;
  |                 ^^ expected (), found str
  |
  = note: expected type `()`
             found type `str`

The explicit call to deref returns a &str, but the operator * returns a str. It's more like you are calling *Deref::deref(&s), ignoring the implied infinite recursion (see docs).

Xirdus is correct in saying

If deref returned a value, it would either be useless because it would always move out, or have semantics that drastically differ from every other function

Although "useless" is a bit strong; it would still be useful for types that implement Copy.

See also:

  • Why does asserting on the result of Deref::deref fail with a type mismatch?

Note that all of the above is effectively true for Index and IndexMut as well.

like image 107
Shepmaster Avatar answered Oct 11 '22 21:10

Shepmaster