Well, the difference is the same as the difference between function arguments and return values. Think of traits and generic types as "type-level functions". That's what they are.
Trait<T>, the type parameter
T is really a type variable that the user of the trait choses. You can say you want a type to implement
Trait<String> or whatever. Many generic types
impl Trait<T> for all choices of
T, for example.
However, in the trait
Item is an associated type. An associated type is something that the implementation of the trait choses, and the user of the trait has no influence on it. Therefore you can't request, for example, an
"some string".chars(). The iterator returned by
str::chars() simply doesn't and can't return an iterator over booleans; its implementation defines that it will yield
One interesting detail is that since a type system is all about constraints, you can still apply bounds and equalities to an associated type in a
where clause, in which case the constraint sort of "propagates" backwards to the implementing type. E.g. the following function will only accept iterators that yield
fn consume_chars<I>(iter: I)
let _: Vec<char> = iter.collect();