This interpretation seems a bit inaccurate as well IMO. Really, the thing here is that the syntax *x
transforms place expression into place expression while Deref::deref
transforms reference into reference. Both things do actually dereference one level — the extra *
in *Deref::deref(&x)
is balanced out by the extra &
, *x
goes from T
to U
while the underlying Deref::deref
call goes from &T
to &U
.
But place expressions are a somewhat weird concept when you first think about them more deeply. When you do things like assigning let y = x
, then the RHS expression x
is evaluated to a value, possibly with effects like moving that value out of x
, whereas in other contexts e. g. x += 1
the expression on the left hand side only refers to the place x.
A x += 1
operation corresponds to a call add_assign(&mut x, 1)
suddenly for taking about the place of x
behind a function abstraction, we need to introduce a mutable reference. Really, with deref
it's more ore less just the same.
The connection to deref coercion works IMO better conceptually if you think about it the other way: Instead of considering *x
to mean *coerce(&x)
(i. e., take reference, then coerce, then remove reference), it might be better to consider *
the more primitive operation and to think of the coercion of some y: &T
into &U
as the compiler sparing you the need to write out the expression &**y
.
- In the expression
&**y
, the&T
turns into*y: T
, into**y: U
and then into&**y: &U
. Only the middle*
convertingT
toU
is not some built-in deref operation for a reference, so it desugars to the*Deref::deref(&…)
expansion, giving&**y
the desugaring&*Deref::deref(&*y)
. Finally, we can simplify by removing redundant&*
combinations, and see how&**y
is essentially the same asDeref::deref(y)
.
One good reason why “considering *x
to mean *coerce(&x)
” might be suboptimal is because coercion works transitively, you can coerce &T
into &V
when T: Deref<Target = U>
and U: Deref<Target = V>
, whereas an expression *x
always only does a single level of Deref::deref
call; you'll need **x
to turn T
into V
.
- For
**x
, the desugaring*Deref::deref(&*Deref::deref(&x))
can again be reduced (by removing redundant&*
) to just*Deref::deref(Deref:deref(&x))
. Similarly,***x
would be*Deref::deref(Deref::deref(Deref:deref(&x)))
. This neatly shows how the change from “reasoning with place expressions” to “working with references”, and back, respectively only needs to happen once in such a chain.