Reputation:
I'd like to create a function which takes a slice of iterators, and combines their elements with a function. The first result would be a function of the first elements of each iterator, the second would be a function of the second elements, etc ...
Visually, vertically three iterators, to the right is the output iterator:
it1 it2 it3 output it
a1 b1 c1 -> f(a1, b1, c1)
a2 b2 c2 -> f(a2, b2, c2)
a3 b3 c3 -> f(a3, b3, c3)
The following does not compile but shows the idea:
pub fn combine<I, A, F, B>(iters: &mut [I], combine_fn: F) -> impl Iterator<Item = B>
where
I: Iterator<Item = A>,
F: Fn(impl Iterator<Item = Option<A>>) -> B,
{
std::iter::from_fn(|| {
let row = iters.iter_mut().map(|it| it.next());
Some(combine_fn(row))
})
}
What am I missing in order to make this function work?
Upvotes: 0
Views: 168
Reputation: 30597
Here is a version that works:
pub fn combine<'a, I, A, F, B>(iters: &'a mut [I], combine_fn: F) -> impl Iterator<Item = B> + 'a
where
I: Iterator<Item = A>,
F: Fn(&mut dyn Iterator<Item = A>) -> B + 'a,
{
std::iter::from_fn(move || {
let mut row = iters.iter_mut().map(|it| it.next()).flatten();
Some(combine_fn(&mut row))
})
}
Key things that needed to be fixed:
The closure passed into from_fn
had to be annotated with move
so that the argument combine_fn
gets moved into the closure rather than referenced from it.
You can't use impl Trait
in a Fn
trait in argument position. An alternative is to use dyn Trait
instead (although that does imply dynamic dispatch).
The row iterator passed into the combine_fn
has to be flattened, otherwise the values returned would be Option<Option<A>>
instead of Option<A>
.
Lifetime annotations are needed to ensure that the output iterator has a lifetime no longer than the lifetime of both the iters
array and any references captured by combine_fn
.
Upvotes: 1