Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the Debug implementation for Vec<T>

Trying to implement the Debug trait for a custom type I stumbled upon the implementation for Vec<T>. I have difficulties understanding how it works.

The implementation goes like this:

impl<T: fmt::Debug> fmt::Debug for Vec<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

I understand it calls the fmt implementation for some other type. What I cannot understand is what type it is. I've tried to figure it out with the help of another question, and searching among the implementations of Debug for something that looks appropriate (maybe something like &[T]), but with no success.

What is the exact meaning of &**self in this context? What implementation of Debug is being called?

like image 736
toro2k Avatar asked May 15 '15 14:05

toro2k


1 Answers

In cases like this, I find it useful to make the compiler tell you what the type is. Just cause a type error and let the compiler diagnostics do it for you. The easiest way is to try to assign your item to something of type ():

fn main() {
    let v = &vec![1,2,3];
    let () = v;
    let () = &**v;
}

The errors are:

<anon>:3:9: 3:11 error: mismatched types:
 expected `&collections::vec::Vec<_>`,
    found `()`
(expected &-ptr,
    found ()) [E0308]
<anon>:3     let () = v;
                 ^~
<anon>:4:9: 4:11 error: mismatched types:
 expected `&[_]`,
    found `()`
(expected &-ptr,
    found ()) [E0308]
<anon>:4     let () = &**v;
                 ^~

Thus v is a &collections::vec::Vec<_> and &**v is a &[_].

More detailed, Vec has this:

impl<T> Deref for Vec<T> {
    type Target = [T];
    // ...
}

So, we dereference once to go from &Vec<T> to a Vec<T>, dereference again to get a [T], and then reference once to get a &[T].

[T] has this:

impl<T> Debug for [T] {
    fn fmt(&self, ...) ...;
}

However, when searching for an appropriate method to call, Rust will automatically attempt to dereference the target. That means we can find the method on [T] from a &[T].

As corrected by Francis Gagné, Debug::fmt takes &self, so directly calling it with a &[T] finds the matching implementation. No need for any automatic referencing or dereferencing.

like image 121
Shepmaster Avatar answered Sep 21 '22 11:09

Shepmaster