Associated types can be used to tell the compiler "these two types between these two implementations are the same". Here's a double dispatch example that compiles, and is almost similar to how the standard library relates iterator to sum types:
trait MySum { type Item; fn sum<I>(iter: I) where I: MyIter<Item = Self::Item>;}trait MyIter { type Item; fn next(&self) {} fn sum<S>(self) where S: MySum<Item = Self::Item>;}struct MyU32;impl MySum for MyU32 { type Item = MyU32; fn sum<I>(iter: I) where I: MyIter<Item = Self::Item>, { iter.next() }}struct MyVec;impl MyIter for MyVec { type Item = MyU32; fn sum<S>(self) where S: MySum<Item = Self::Item>, { S::sum::<Self>(self) }}fn main() {}Also, https://blog.thomasheartman.com/posts/on-generics-and-associated-types has some good information on this as well:
In short, use generics when you want to type
Ato be able to implement a trait any number of times for different type parameters, such as in the case of the From trait.
Use associated types if it makes sense for a type to only implement the trait once, such as with Iterator and Deref.