These blanket implementations aren’t always the easiest thing to find, especially if you haven’t yet learned to look for them. Another trait famous for having such an implementation is Iterator
. Both Iterator
and Write
also do somewhat advertise the existence of these impls by offering by_ref
convenience methods: Iterator::by_ref
Write::by_ref
.
In principal, any trait that doesn’t have any fn …(self)
methods but only &self
and &mut self
ones – at least as far as the ones without default implementations are concerned (and which doesn’t otherwise use the Self
type in function signature in ways that require ownership, can be implemented for &mut T
based on an impl for T
, and it’s often a good idea to do so if possible. (Also due to how orphan rules work, if you don’t write such an implementation for a trait, then adding it later may be a breaking change.) Similarly for &T
if no methods require mutable access, either.
Hence it’s unsurprising that actually there’s quite a few traits that do the same (but – except for Read
–not featuring a by_ref
method). Probably because immutability is always a bit less surprising, no-one will give a second thought about various immutable-access-only traits having implementations for &T
based on the one for T
.
This would include Display
and the other formatting traits, Ord
and the other comparison and hashing traits, which all support &T
and &mut T
(incidentally Hasher
, not a hashing trait, has an impl for &mut T
, too).
The situation for operator traits is a bit complex… while many these traits take operands by-value anyways, the likes of Add
features tons of implementations for various reference types, too. The operator overloading traits that do work with &mut self
only, like AddAssign
or IndexMut
, don’t have a generic implementation for &mut T
, but that’s probably because we want these operator overloading traits to be as custom-implementable for users as they like. FnOnce
on the other hand famously has an impementation for &mut F
, and Fn
for &F
and &mut F
, and these are commonly very useful, if you need to share a or borrow a closure without consuming it, but then pass the result into some general x: impl FnOnce
for example (though of course wrapping a closure with a new closure would’ve also always been possible to do such a call).
The traits AsRef
/AsMut
and Borrow
/BorrowMut
are infamous for having implementations for &T
and &mut T
that differ in whether or not any underlying implementation for T
is delegated to. AsRef
then goes on and makes the unfortunate design choice to not do the same delegation for other smart pointer types.
The trait Error
has an implementation for &T
. ToOwned
doesn’t feature any implementation for &T
, but such an implementation would be impossible due to how the implementation for Borrow
is defined (which was a topic in the previous paragraph).
With this, I think I’ve made it through most of the list of standard library traits that are presented here, skipping the ones that use Self
in an owned fashion. Similar considerations apply to Box<T>
implementations, too, except that it even supports ownership, and is famously implemented for FnOnce
, too, and probably for most traits discussed above; and maybe more? (I’m not looking into that right now.)
Edit, also worth mentioning, fmt::Write
which also has an implementation for &mut T
, but doesn’t feature a by_ref
method.