What does `&**self` mean?

This code is from standard library. what does &**self here?

impl AsRef<OsStr> for String {
    #[inline]
    fn as_ref(&self) -> &OsStr {
        (&**self).as_ref()
    }
}

Follow the individual expressions from innermost to outermost:

  • self is of type &String. This is determined by the function signature. So, it's a pointer to a pointer to text.
  • *self is of type String; we've looked at where the reference points.
  • **self is of type str; we've looked at where the String points.
  • &**self is of type &str; we've taken a reference to the str.
  • Therefore, the as_ref() call's input is &str and its output is &OsStr, so it must be calling the impl AsRef<OsStr> for str.

In general, &**self will appear when:

  • you have some type that's a pointer (here, String)
  • you are implementing a trait method whose signature contains &self (here, AsRef::as_ref())
  • you need specifically a reference to what the pointer type you're working with points to (here, str)

Often this sort of deep dereferencing is unnecessary because method lookup will auto-dereference for you, but in this case, self.as_ref() would just end up invoking impl AsRef<OsStr> for String itself, creating infinite recursion. Explicitly dereferencing reaches the implementation that is actually needed.

14 Likes

In this sort of situation, I usually prefer to use a more explicit form of the call so that I get a compile error instead of infinite recursion if I get something wrong:

str::as_ref(&**self)

or

self.as_str().as_ref()

Nit: Because as_ref takes &self, the relevant implementation is actually AsRef<OsStr> for str.

6 Likes

how do we know *String will result in str? there is any code in the std library for that?

Yes; the deref operator * is overloaded for String via an implementation of std::ops::Deref<Target=str>.

1 Like

Whoops, yes, of course. I knew that, but wrote the wrong thing. Fixed.

1 Like

additionally, this style can be used to then rely on deref-coercion, and write:

str::as_ref(self)
7 Likes