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?
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)
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
}.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With