use std::iter::IntoIterator;
fn weird_into_iterator_trait_bound<T:IntoIterator>(x:T) {
for _ in x.into_iter() {
println!("Hello");
}
}
fn it_is_fine_when_not_generic (x:[i32; 3]) {
for _ in x.into_iter() {
println!("Hello");
}
}
fn main() {
let x: [i32; 3] = [1, 2, 3];
//weird_into_iterator_trait_bound(x); // x must be Iterator???
it_is_fine_when_not_generic(x);
}
Building with the second line of main uncommented errors out with
src/main.rs:17:5: 17:36 error: the trait `core::iter::Iterator` is not implemented for the type `[i32; 3]` [E0277]
src/main.rs:17 weird_into_iterator_trait_bound(x); // x must be Iterator???
Why this? Is there some other bound I need to use to allow T to implement FromIterator and not Iterator?
This is because there is a generic impl of IntoIterator for all types T if they are also Iterator (that is, an iterator is trivially convertable into an iterator).
Therefore, since [i32; 3] does not impl IntoIterator, Rust considers this generic impl and demands its bound to be satisfied.
I was sure this was wrong until I checked the documentation which says that IntoIterator is implemented for &[T; N], which is good enough for methods but not, I see, for trait bounds. I tried changing to weird_into_iterator_trait_bound(&x), which compiled without complaint.
I ran into this problem trying to convert to a generic a function that takes array references as arguments. I want to continue taking references so I was writing fn foo<T: IntoIterator>(x:&T) which was breaking all my existing calls by inferring an array for T instead of an &array.
I expected that to call fn foo<T:IntoIterator>(x:T) on &Vec would error because Vec implements IntoIterator for Vec, not IntoIterator for &Vec, but trying it just now passing a reference works fine, so I think my problem is resolved.