Why does T:IntoIterator cause the compiler to demand T:Iterator?

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.

2 Likes

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.

In this case, the &Vec<X> is being auto-deref'd to a &[X], which also implements IntoIterator.

Also, you don't need to call explicitly an .into_iter() method in your for _ in x clauses, for loop works with IntoIterator just fine.