How to most generically iterate a sequence of items with a given type?

rust

Solution

Let's look at what the types are for your first case:

for i in &["foo".to_string()] {
    let () = i;
    // expected `&collections::string::String`,
    // found `()`
}

That is, the type of your iteration variable is `&String`, not on `String`, as your function wants. The same thing happens for your second case. The third case works:

for i in vec!["foo".to_string()] {
    let () = i;
    // expected `collections::string::String`,
    // found `()`
}

We can look at the implementation for `IntoIter` for arrays and for all 3 forms of Vec. Note that the implementation for `Vec<T>` consumes the vector, whereas the one for `&Vec<T>` must return an iterator over references to the elements.

You can't consume an array, so that iterator must always return references.

Here's an example that uses the `AsRef` trait that should do what you want:

use std::iter::IntoIterator;

fn iterate<I, S>(v: I)
    where I: IntoIterator<Item=S>,
          S: AsRef<str>
{}

fn main() {
    iterate(&["foo"]);
    iterate(&["foo".to_string()]);
    iterate(["foo".to_string()].iter());
    iterate(vec!["foo".to_string()]);
    iterate(&vec!["foo".to_string()]);
}

This says that we expect any concrete type that implements the trait `Iterator`. That iterator must yield a type that implements the trait `AsRef<str>`, allowing us to pass in {arrays,vectors,slices} of {`String`,`&str`}.

Problem

The code below best describes the issue. ``` use std::iter::IntoIterator; fn iterate<I: IntoIterator<Item=String>>(v: I) { } // iterate(&["foo".to_string()]) // error: type mismatch resolving `<&[collections::string::String; 1] as core::iter::IntoIterator>::Item == collections::string::String`: // expected &-ptr, // found struct `collections::string::String` [E0271] // iterate(["foo".to_string()].iter()) // type mismatch resolving `<core::slice::Iter<'_, collections::string::String> as core::iter::IntoIterator>::Item == collections::string::String`: // expected &-ptr, // found struct `collections::string::String` [E0271] // This works ! iterate(vec!["foo".to_string()]) ``` How can I iterate anything (with a given item type) generically? Additional Notes The intention is to allow users of such a function to pass in anything that can be iterated, or converted into an iterator. Also I have the feeling that the actual issue is not really described in the compiler error - as the type it sees seems to be different from what it shows. I am using `rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-19)`

Original source