There are really two questions here:
What types can be dereferenced?
A type can be “dereferenced” if it acts like a pointer to some other type. For example, &T
and Box<T>
and *mut T
and Rc<T>
are all different types of “pointer to a T
.” (For example, dereferencing an &bool
produces a bool
).
In addition to these generic pointer types, there are a few specialized “pointer-like” types for managing slices: String
is a specialized pointer to a str
slice, and Vec<T>
is a specialized pointer to a [T]
slice.
All dereferenceable types implement the Deref
and/or DerefMut
traits, and can be deferenced with the *
operator.
/// Convert from `&bool` to `bool` by dereferencing.
fn foo(b: &bool) -> bool { *b }
(Note: Raw pointers are a special exception. You can dereference them with *
but only in unsafe
code, and they don't implement Deref
or DerefMut
because those can be called in safe code.)
Non-pointer types like bool
or char
or (u8, u8)
cannot be dereferenced: They do not implement the Deref
trait and do not act like pointers to some other type.
When does dereferencing happen automatically?
Whenever you use the .
(“dot”) operator to access fields or methods of a value, the expression on the left-hand side of the dot is auto-referenced and/or auto-dereferenced automatically.
For example, if x
has type &i32
, then writing x.count_ones()
is shorthand for (*x).count_ones()
, because the count_ones
method requires an i32
.
Rust will also insert automatic dereferencing as part of deref coercion. This is a special coercion that can only convert from one reference type to another. For example, this is what lets you convert from String
to &str
by writing &x
instead of &*x
.
These auto-ref/deref rules exist just to make Rust code less noisy to read and write. Without them, Rust would often require you to write things like (&mut *foo).send(&**bar)
instead of foo.send(&bar)
.