Why does the as_ref method return self?

This code snippet is taken from the standard library implementation of the AsRef trait for String.

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

What I understand from the above code snippet is that we want to convert &String to &str.

why does the as_ref method return self in the above code snippet? Because the self is String, we want to convert &String to &str, so the as_ref should not return self, it should somehow convert String into str and then return a reference to str or it simply returns &self that will convert it into &str.

At least the return expression of the as_ref method should be self.as_str(). Also, I found that the as_ref method of String also returns a plain self.

I think I am clearly missing something to connect the dots.

Deref coercion converts a reference to a type that implements the Deref trait into a reference to another type. For example, deref coercion can convert &String to &str because String implements the Deref trait such that it returns &str .

https://doc.rust-lang.org/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods

5 Likes

At least the return expression could have been written like &self then it could be more clear, but, no, it is just a plain self.

Then what is the point of the AsRef trait?

&self would need even more conversion, as its type is &&String. It wouldn't be any clearer.

What do you mean "then"? The point of the AsRef trait is independent of exactly how it is implemented for specific types.

I thought that inside the body of the as_ref method, the self is simply a plain self. From your comment now I understand that inside the method body, the self remains behind reference.

I meant that deref coercions also implicitly convert a reference type to another, so it could have served the role the AsRef trait serves

No, it is declared as &self in the method signature, which is what matters. &self as a receiver means self: &Self, ie. the variable self has type "reference to the type being implemented".

I meant that deref coercions also implicitly convert a reference type to another, so it could have served the role the AsRef trait serves

No, they have intentionally different roles. Deref is for smart pointers when there is a single unambiguous type to which the smart pointer dereferences. AsRef, in contrast, is for generic reference-to-reference conversions. For example, String implements both AsRef<str> and AsRef<[u8]>.

3 Likes

There's a really important difference between Deref and AsRef; for a given type T (e.g. String), you can only have one implementation of Deref, which tells you what type you get during deref coercion, but you can have as many implementations of AsRef as you find useful.

So &String becomes &str via deref coercion - nothing else is possible - while it has implementations of AsRef<str>, AsRef<[u8]>, AsRef<OsStr> and AsRef<Path> to let you convert an &String into an &[u8], &OsStr, &Path etc.

4 Likes

Others have given more detail, but to make sure the core point is clear: it's for writing generic functions, like fn foo<S: AsRef<str>>(input: &S) or fn foo<B: AsRef<[u8]>>(input: &B)

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.