fn foo<T>(t: T) {
// do stuff
t.iter() ...
}
I have this function where the concrete types passed are either a Vec<(String, String)>
or a HashSet<(String, String)>
.
Inside it I want to iterate over the collection twice without cloning or first collecting to a Vec
. Both types have the iter()
method available which doesn't consume, but no trait exists to bound the generic type by to allow me to access it.
Is there a better way than to define a custom ad hoc trait Iter
for both Vec
and HashSet
?
I'd use IntoIterator
as a trait bound on T
to accomplish what you want. IntoIterator
is implemented for both &'a Vec<T>
and &'a HashSet<T>
, so you can pass a reference to your vector or hash set to foo
without consuming either, enabling you to iterate over the values as often as you like:
use std::collections::HashSet;
fn foo<'a, T>(t: T)
where
T: IntoIterator<Item = &'a (String, String)> + Copy,
{
for (k, v) in t {
println!("{k}: {v}");
}
for (k, v) in t {
println!("{k}: {v}");
}
}
fn main() {
let map: HashSet<(String, String)> = HashSet::from_iter([("foo".to_owned(), "bar".to_owned())]);
let vec = vec![("foo".to_owned(), "bar".to_owned())];
foo(&map);
foo(&vec);
}
stdout:
foo: bar
foo: bar
foo: bar
foo: bar
Note that we need the Copy
trait bound on T
to tell static analysis that we are not moving out of t
in our first loop. This bound is no problem though, because references are always Copy
, regardless of the referent.