I've got some code that needs to accept a list of data structures that could be any of a number of different types, but which all implement Into<SomeType>
. So, I say that the parameter is impl IntoIterator<Item = Into<SomeType>>
and I'm done. Except...
I can't seem to be able to specify "an empty list" in a concise manner.
Am I screwed, and everyone will just have to use an ugly syntax (Vec::<impl Into<SomeType>>::new()
), or is there a simple option I haven't come across before?
Here's example code that demonstrates the problem (also in the playground):
fn takes_iterable_arrays(ia: impl IntoIterator<Item = impl Into<String> + std::fmt::Debug>) {
println!("{:?}", ia.into_iter().collect::<Vec<_>>());
}
fn main() {
takes_iterable_arrays(vec!["foo", "bar"]);
takes_iterable_arrays(Vec::<String>::new());
takes_iterable_arrays(Vec::<&str>::new());
//takes_iterable_arrays(vec![]);
//takes_iterable_arrays(&[]);
//takes_iterable_arrays([]);
}
The commented-out lines are the variations that I've tried, that I'd like to use, but don't work.
It's impossible to provide “an empty list” without specifying the element type, because takes_iterable_arrays()
could decide to change its behavior based on the type (using size_of()
or type_name_of()
) even if there are no elements.
So, you're stuck with roughly as much syntax as you're already using. Perhaps the shortest empty IntoIterator
you could use is None::<&str>
, but that's on the cryptic side. You could add a generic parameter for the element type:
fn takes_iterable_arrays<T>(ia: impl IntoIterator<Item = T>)
where
T: Into<String> + std::fmt::Debug,
{
println!("{:?}", ia.into_iter().collect::<Vec<_>>());
}
This means that takes_iterable_arrays::<&str>([])
is a valid call. It can also help the caller constrain the item type if they're dealing with a generic iterator return type themselves.