AFAIK scan iterator method is the only iterator method that provides a mechanism to share some mutable state across iterations. But I think this method is too complicated and wide, therefore it should be replaced by more convenient and simple methods.
Let's look at scan usage example:
let a = [1, 2, 3];
let mut iter = a.iter().scan(1, |state, &x| {
// each iteration, we'll multiply the state by the element
*state = *state * x;
// then, we'll yield the negation of the state
Some(-*state)
});
assert_eq!(iter.next(), Some(-1));
assert_eq!(iter.next(), Some(-2));
assert_eq!(iter.next(), Some(-6));
assert_eq!(iter.next(), None);
Observations:
- We must provide an initial value of the
state, we can't get it from the first iteration. -
stateis provided by&mutreference, so we must change it by using*state = ...syntax, not by returning a value. So, we always need curly brackets. But it's a powerful tool: we can compute a return value before changing state, or after. - Then we return
Some()of next value. And by this we do as same asfilter_map. Because of thisScandoesn't implementExactSizeIterator, so we can't use it to allocate exact space when using thecollectmethod.
I think:
- We should able to provide initial value either by telling an exact value or from first iteration.
-
stateshould be changed not by mutable reference, but by functionFn(State, &Item) -> State, because it is more simple and don't require{}in simple cases. - There shouldn't be
filter_mapormaporfilterbehavior inside this iterator, it should be done by the next iterator adaptors.
So, I suggest these new methods to replace scan: state_before, state_after with equal signatures.
Example:
let a = [1, 2, 3];
assert_eq!(a.iter().state_before(None, |state, &item| state * item).eq(&[(1, 1), (2, 2), (6, 3)]));
assert_eq!(a.iter().state_before(Some(4), |state, &item| state * item).eq(&[(4, 1), (8, 2), (24, 3)]));
assert_eq!(a.iter().state_after(None, |state, &item| state * item).eq(&[(1, 1), (1, 2), (2, 3)]));
assert_eq!(a.iter().state_after(Some(4), |state, &item| state * item).eq(&[(4, 1), (4, 2), (8, 3)]));
- First argument of these methods - is an initial value. If it is
None, then the initial value is yielded from the first iteration. If it isSome(...), then it initialized by the inner value. - Second arguments of this methods - is function
Fn(State, &Item) -> State. That function receives current state and current item by reference and it must return next state value. - The main name is
statebecause these methods provide state across iterations. - Suffix
beforemeans that the state will be modified before returning the element. Suffixaftermeans that the state will be modified after returning the element. - These methods return an iterator with
Item = (State, OldItem)by analogy asenumerate. - These methods return an iterator that implements
ExactSizeIterator. - Then, we can apply
filter_mapnext and get the same behavior as ascan.
What do you think?

