Implementing a trait for Foo implements it for the type Foo, implementing a trait &Foo implements it specifically for the reference, which a reference is a different type.
Implementing a trait on Foo allows the methods to take ownership of the struct. This allows you to perform actions that a reference couldn't do, such as destroying the struct, moving the struct onto a new thread, or transforming the struct into a different type, such as in the case with the Iterator trait's map function.
Note: You can implement a trait on a type and have methods that take a reference
trait MyTrait {
fn ownership_function(self); // takes ownership of self
fn borrow_function(&self); // takes a reference to self
fn mut_borrow_function(&mut self); // takes a mutable reference to self
}
Generally you want to implement a trait on the type itself. It's also useful if you plan on using generics or trait objects. For example you would be able to create a vector of types that implement the MyTrait.
impl Trait for Foo is the normal case. Each trait method can then decide whether it takes self or &self or &mut self, so they may be callable on Foo, &Foo and/or &mut Foo, as appropriate.
impl Trait for &Foo is useful in some special cases. For example, the std::io::Write trait has methods that take &mut self because in many cases they need to mutate the writer. But some types, like File, can implement these methods without needing exclusive mutable access. For these types, we have impls like impl Write for &File. Now you can write to a File through a shared reference as well as a mutable one.
Implementing a trait for a reference type can also be used just as a convenience. For example, it can let callers pass an argument to a generic function without explicitly dereferencing it. In this case, it just makes the code look cleaner; it doesn't add any new capabilities.
It’s also sometimes used to allow more efficient code. For example, most of Iterator‘s methods take self so that the adapters can tear apart the source iterator. To make iterators reusable, the standard library also defines an implementation for mutable references:
impl<I:Iterator> Iterator for &mut I { /* ... */ }