What's the reason of implementing AsRef<T> for T?

Why do we need to implement AsRef<T> for T and then get a reference of T by as_ref? why not just use &T?

I'm not sure I understand what you are referring to? There is no impl AsRef<T> for T implementation in the standard library. There is one for impl AsRef<T> for &T, so I don't see why you wouldn't be able to just pass &T to an interface that expects AsRef<T>.

This is an example from path:

impl AsRef<Path> for Path {
    fn as_ref(&self) -> &Path {
        self
    }
}

Sorry for any added confusion from my previous answer, but there is no impl AsRef<T> for &T implementation, the one I linked is for impl AsRef<U> for &T where T: AsRef<U>. So indeed if we want to pass a &T to something that expects AsRef<T>, T must implement AsRef<T>, you are completely right. Read more about it in AsRef in std::convert - Rust. The Borrow trait on the other hand is reflexive, so you might want to use it instead of AsRef.

1 Like

Ideally every type T would implement AsRef<T>. But due to coherence -- the necessity to avoid overlapping implementations -- one has to choose between a blanket "lifting over references" implementation and a blanket "reflective" implementation.

Since AsRef<T> got the blanket "lifting over references" implementation (in contrast with Borrow), every type has to supply the reflexive implementation individually. (Why there isn't a builtin derive to make this more common, I couldn't say.)

5 Likes

I assume it's purely for convenience. I think it's obvious why there is impl AsRef<Path> for PathBuf? But PathBuf and &Path are often used interchangeably in code, and PathBuf: Deref<Output=Path>. This can lead to some minor user confusion whether your variable is &Path or &PathBuf. Implementing AsRef<Path> for Path allows end users to treat those cases uniformly, without annoying compiler errors, and it also makes refactoring owned and borrowed paths a bit easier.

I don't think it's common to impl AsRef<T> for T otherwise.

1 Like