Well…
If Foo
implements Deref
, and you have x: Foo
, then *x
is of type Foo::Target
.
The type Target
in the implementation for Vec<T>: Deref
is [T]
, not &[T]
.
The return type of the Deref::deref
method is &[T]
, but that fits the picture of *vec
desugaring to *Deref::deref(&vec)
. Here
vec: Vec<T>
&vec: &Vec<T>
Deref::deref: fn(&Vec<T>) -> &[T]
- so,
Deref::deref(&vec): &[T]
- and finally
*Deref::deref(&vec): [T]
By the way, in light of this desugaring, to achieve the equivalent of Deref::deref(some_expr)
, but using the “*
” operator, you’ll need to write &**some_expr
.
Of the two *
’s, the right one operates on some_expression: &…
some primitive shared reference type, so only the left *
is desugared.
&**some_expr
hence desugars to &*Deref::deref(&*some_expr)
, and the operation &*
on a shared reference is a no-op in each case, which means this is essentially Deref::deref(some_expr)
, as expected.
This also gives an easy intuitive meaning to the &**self
in the original question: It’s a way to achieve the same as a call to the deref
function.
By the way, if you find this syntax weird (and also rarely see it), that’s because a lot of dereferencing in Rust can happen automatically. For the code in question, it’s mainly done to avoid accidentally defining a recursive function; method resolution or implicit coercions of references (those two things are the possibilities for automatic dereferencing in Rust) wouldn’t help here.
However, the code can be written arguably more cleanly, by specifying the implementor of the index
method, the type [T]
. The function
impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
Index::index(&**self, index)
}
}
could thus be re-written more explicitly as
impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
<[T] as Index<I>>::index(&**self, index)
}
}
or slightly less explicit, but still specifying the required self
-type of the ::index
method using
impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
<[T]>::index(&**self, index)
}
}
Now that the first argument’s type for <[T]>::index
is clearly indicated, we can use automatic dereferencing and simply write
impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
<[T]>::index(self, index)
}
}