Is there any way to pass somestring.chars()
or somestring.bytes()
to a function and allow that function to reconstruct the iterator?
An example is below. The goal is for the function to be able to iterate through coll
multiple times, reconstructing it as needed using into_iter()
. It works correctly for vectors and arrays, but I have not been able to get it working for the string iterator methods.
// Lifetime needed to indicate the iterator objects
// don't disappear
fn test_single<'a, I, T>(collection: &'a I)
where
&'a I: IntoIterator<Item = T>,
T: Display,
{
let count = collection.into_iter().count();
println!("Len: {}", count);
for x in collection.into_iter() {
println!("Item: {}", x);
}
}
fn main() {
// Works
test_single(&[1, 2, 3, 4]);
test_single(&vec!['a', 'b', 'c', 'd']);
let s = "abcd";
// Desired usage; does not work
// test_single(&s.chars());
// test_single(&s.bytes());
}
The general error is that Iterator
is not implemented for &Chars<'_>
. This doesn't make sense because chars definitely does implement IntoIterator
and Iterator
Is there a solution that allows for the desired usage of test_single(&s.chars())
?
Link to the playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=230ee86cd109384a1c62c362aed9d47f
(IntoIterator
is prefered over Iterator
for my application, since I also need to specify that IntoIterator::IntoIter
is a DoubleEndedIterator
.)
CodePudding user response:
This can work but not the way you have it written.
You can't iterate a shared reference because Iterator::next()
takes &mut self
. IntoIterator::into_iter()
could be made to work with e.g. &Chars
, but that's not necessary because Chars
and Bytes
both implement Clone
, which creates a copy of the iterator (but doesn't duplicate the underlying data).
So you just need to adjust your bounds and accept the iterator by value, cloning it when you will need another iterator later:
fn test_single<I, T>(collection: I)
where
I: Clone IntoIterator<Item = T>,
T: Display,
{
let count = collection.clone().into_iter().count();
println!("Len: {}", count);
for x in collection.into_iter() {
println!("Item {}", x);
}
}
Now you can call test_single(s.chars())
, for example.
Side note: You can express the type I
purely with impl
, which might be more readable:
fn test_single(collection: impl Clone IntoIterator<Item=impl Display>) {