Why does the Rust standard library implement traits for both Thing and &Thing?

Why does the Rust standard library implement traits for both Thing and &Thing?

Problem Description:

I was reading the question The trait `std::fmt::Write` is not implemented for `Stdout` when it should be where the asker noted that the rust documentation shows that the std::io::Write trait is implemented for both &Stdout and Stdout.

I don’t understand why this is necessary or how you would use it. Isn’t everything you define for Thing always implemented for &Thing? Why would you implement something for &Thing without implementing it for it’s definition?

Solution – 1

Isn’t everything you define for Thing always implemented for &Thing?

No, an implementation for a type T will not automatically implement anything for &T. Now, sometimes blanket implementations can kick in, and if you pass a &&T to a function expecting a &T, then Rust will insert dereferences for you, but that does not mean the trait was implemented for &T, just that Rust helped you out a bit.

Why would you implement something for &Thing without implementing it for it’s definition?

There’s a very good example of that which we use all the time: String::from.

impl From<&str> for String {
  fn from(value: &str) -> String {
    ...
  }
}

From::<T>::from takes an argument, by value. No references or anything, just straight-up a value of type T. So we can never write a From<str> implementation for anything, since str is unsized and hence cannot be a function argument on its own. But it makes perfect sense to convert a &str to a String: that’s just making an owned copy of the string.

Solution – 2

Building on @Silvio-Mayolo’s answer: in this particular case, there was originally just an implementation for Stdout; and the more-flexible implementation for &Stdout was added later, which provides a strict superset of functionality, notably allowing you to share the reference between threads. The original implementation can’t be removed without breaking backwards compatibility with existing code using the by-value implementation (auto-deref isn’t perfect, you would still need to go back and add an & in some situations).

Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject