I am trying to write a function that takes any iterable to a generic type as input and loops over the elements. Here is a working example
pub fn test1<'a, IterableT, ItemT>(nodes: &'a IterableT)
where
&'a IterableT: IntoIterator<Item = &'a ItemT>,
ItemT: 'a + Debug
{
for x in nodes {
println!("consuming or iterating: {:?}!", x);
}
}
This works with reference types. I struggle to implement a version that works with both regular types and references. The closest I have got it the following
pub fn test1<IterableT>(nodes: IterableT)
where
IterableT: IntoIterator,
IterableT::Item: Debug
{
for x in nodes {
println!("consuming or iterating: {:?}!", x);
}
}
This works as long as the reference version of the type I am using implements IntoIterator (for example vec
, &vec
and &mut vec
). The problem is that I can't reintroduce the ItemT
generic since then the underlying Item
is narrowed down to one of Item
or &Item
pub fn test1<IterableT, ItemT>(nodes: IterableT)
where
IterableT: IntoIterator<Item = ItemT>, // alternatively IntoIterator<Item = &ItemT>
ItemT: Debug
{
for x in nodes {
println!("consuming or iterating: {:?}!", x);
}
}
Depending on whether I use IntoIterator<Item = ItemT>
or IntoIterator<Item = &ItemT>
, this works with vec
or &vec
but not both. A hacky workaround is to specify IterableT::Item: Into<ItemT>
, but this only works if the underlying type implements the Into traits (so this will work with built-in types like i32, i64, but not for some custom made struct).
Is there a way to indicate that Item
can either be ItemT
or &ItemT
in the where
clause? The reason I need to introduce ItemT
is because it is a generic variable of the parent struct that this function is a part of. I need to accept iterators specifically with that type.
You can use
std::borrow::Borrow
to treatT
and&T
the same.In action:
Output:
Note that because the
Borrow
trait has a type parameter, you have to provide the correct type forT
explicitly at the call site; Rust will not be able to infer the type you want.