I'm trying to work out how to write functions that take generic iterable collection parameters, and it's been very tricky to figure out how to structure them. I've worked out some of the cases by trial and error, but I'm stumped at one. I want to be able to call a function like this:
let result = analyze_items(&collection);
…or perhaps:
let result = analyze_items(collection.iter());
…which I find less aesthetically pleasing (because it's not as clear that collection
is not consumed in the process), but acceptable.
I've experimented with many different variations, and found a few things that work. First, there's the case where I want to accept only one type of collection:
fn analyze_items1<T>(collection: &Vec<T>)
where
T: std::fmt::Display,
{
for item in collection {
println!("{}", item);
}
}
This one is nice in that I can just pass &collection
as the parameter, rather than explicitly calling collection.iter()
.
I also found a way to make both Iterator
and Iterator::Item
generic:
fn analyze_items2<T>(collection: impl Iterator<Item = T>)
where
T: std::fmt::Display,
{
for item in collection {
println!("{}", item);
}
}
This requires calling collection.iter()
, rather than just passing a reference to the collection to the function, but it does work.
Last, for certain types, I can specify a concrete type for Iterator::Item
:
fn analyze_items3<'a>(collection: impl Iterator<Item = &'a i32>) {
for item in collection {
println!("{}", item);
}
}
Unfortunately, this doesn't work if the Item
I want to use it on is of type &str
(or any other reference type? I'm not sure). Can anyone tell me how I could rewrite this to operate on a Vec<&str>
rather than a Vec<i32>
? Or explain a better way to do this in general; I really feel like there should be a way for me to pass a generic collection that implements Iterator
by immutable reference to a function, but I haven't been able to find it on my own.