I am struggling to find a clean/idiomatic approach to partition an iterator into a fixed number of sub parts based on Enum variants.
enum State {
A(A),
B(B),
C(C),
}
let states = vec![A(...), C(...), ...]; // Some iterable structure containing State
I wish to construct three iterators which process the A
s, B
s, and C
s separately. Here's an approach I tried that failed:
Use filter_map
.
let As = states.iter().filter_map(|s| match s {
State::A(a) => Some(a)
_ => None
});
let Bs = states.iter().filter_map(|s| match s {
State::B(b) => Some(b)
_ => None
})
let Cs = ...
I see three issues with this approach:
Firstly, this will not work if mutable references are required, as taking iter_mut
on both would result in the compiler believing states
is mutably borrowed multiple times.
Secondly, the compiler cannot check if all variants are handled, which does not feel very idiomatic.
Finally, we consume the iterator three times. If we just had an iterator over the source data (instead of the actual array in my example), this would not be possible.
Answering the questions in title - there is no idiomatic way to partition iterator into multiple iterators, since this would require essentially unlimited buffering.
The problem is that, after partitioning, every iterator must be able to be iterated independently, in particular, it can be exhausted (using collect
, for example). This means that one must exhaust the original iterator, to be sure that this partition will not have any more items. This means that one must store all items from other partitions somewhere, so that their corresponding iterators could be driven to completion afterwards.
Therefore, an idiomatic way is not to partition into iterators, but do what is done in OP's own answer - exhaust the source iterator and build several Vec
s out of it, which can then be handled separately.