My use-case is that I want to scan over an iterator, and yield accumulated values over segments of the original iterator (this is for a tokenizer). In other words, it's not a 1-to-1 mapping between the input values and output values. Note that filter_map()
won't work because I do need the accumulator value.
I found .scan()
, which is almost what I want:
#![allow(unused)]
fn main() {
let a = [1, 2, 3];
let mut iter = a.iter().scan(1, |state, &x| {
if x == 2 {
return None;
}
// each iteration, we'll multiply the state by the element
*state = *state * x;
// then, we'll yield the negation of the state
Some(-*state)
});
println!("{:?}", &iter.next());
println!("{:?}", &iter.next());
println!("{:?}", &iter.next());
}
Except that the above outputs
Some(-1)
None
Some(-3)
When I want it to output
Some(-1)
Some(-3)
None
And, despite what you might think, this doesn't work:
Some(-*state)
}).filter(|x| x.is_some());
Because I'm not actually iterating over Option
s:
error[E0599]: no method named `is_some` found for reference `&{integer}` in the current scope
--> src/main.rs:15:21
|
15 | }).filter(|x| x.is_some());
| ^^^^^^^ method not found in `&{integer}`
So it's like iterator methods are intentionally shielded from the "missing yield value" case.
Any ideas how I can a) filter out those missing yields, or b) accomplish the above in some totally different way?
You can use filter_map
and make your own accumulator in a variable outside the iterator:
fn main() {
let a = [1, 2, 3];
let mut state = 1;
let mut iter = a.iter().filter_map(|&x| {
if x == 2 {
return None;
}
// each iteration, we'll multiply the state by the element
state = state * x;
// then, we'll yield the negation of the state
Some(-state)
});
println!("{:?}", &iter.next()); // Some(-1)
println!("{:?}", &iter.next()); // Some(-3)
println!("{:?}", &iter.next()); // None
}