In Rust you could have both Iterators if it had a type parameter.
In Rust you could have both Iterators if it had a type parameter.
An illustrative example of the difference: `AsRef<T>` and `Deref` have almost identical signatures, except that the target type for `AsRef` is a parameter and for `Deref` is an associated type. `String` implements `AsRef<str>`, `AsRef<Path>`, and so on, but only `Deref<Target = str>`.
The blog post's meandering description the difference between static and dynamic dispatch has no relevance whatsoever.
I'm not sure how or if Rust traits can be used as function parameters - can I have a function that takes a parameter of type Iter? Can it take any implementation of Iter than, regardless of what item type that returns? How would I define a function that only accepts iterators that return, say, i32 items?
fn foo<I>(it: I) where I : Iterator<Item = i32> {}
fn example<I: Iterator>(iter: I) { ... }
// or:
fn example<I>(iter: I) where I: Iterator { ... }
// or:
fn example(iter: impl Iterator) { ... }
> Can it take any implementation of Iter than, regardless of what item type that returns?Yes, in the above example. Then, the item type can be referred to as "<I as Iterator>::Item", or "I::Item" for short, unless you use the "impl Trait" syntax. You can also give the item type a name by giving it its own type parameter:
fn example<T, I: Iterator<Item = T>>(iter: I) { ... }
> How would I define a function that only accepts iterators that return, say, i32 items? fn example<I: Iterator<Item = i32>>(iter: I) { ... }
// etc., just write Iterator<Item = i32> in place of Iterator class FooIterator implements Iterator<Foo>{…}
class BarIterator implements Iterator<Bar>{…}
class MyCollection {
public Iterator<Foo> foos { return new FooIterator(this); };
public Iterator<Foo> bars { return new BarIterator(this); };
}
It would matter for Iterable. You cannot have this: class MyCollection implements Iterable<Foo>, Iterable<Bar>{…}
, but there, there’s a second problem: in Java, you can’t have overloads that only differ in their return type.The benefits of using an associated type (compared to using a generic parameter in Rust, not compared to Java) include clarity, possibly improving type inference, and avoiding issues with crate coherence by requiring that the Iterator impl live in the crate that defines the input type, rather than the one that defines the output type.