I'm just curious as to why A doesn't exist as a shorthand for B or C.
fn main() {
let opts = [Some(1), None, Some(2)];
// A
for Some(n) in opts {
println!("{n}");
}
// B
for o in opts {
if let Some(n) = o {
println!("{n}");
}
}
// C
for o in opts {
let Some(n) = o else { continue };
println!("{n}");
}
}
The “why” I see is that if for’s pattern skipped non-matching items, then it would be possible to accidentally write a for loop that skipped items, when the intent was just to do destructuring, not filtering. You can add filtering ability with an if let, but you cannot subtract filtering from a for that had it built in.
there's ambigiouty here, if such syntax were to be supported, what's the obvious intention???
for instance, besides the "filtering" behavior like case B or C in your example, there's also the possibility of take_while() behavior. compare:
for n in opts.into_iter().filter(Option::is_some) {
//...
}
for n in opts.into_iter().take_while(Option::is_some) {
//...
}
your example can just be written with filter_map():
// using closure
for n in opts.into_iter().filter_map(|x| x) {
}
// using a named function
fn id<T>(x: T) -> T { x }
for n in opts.into_iter().filter_map(id) {
}
// wrapping in a helper function:
fn filter_some<T>(it: impl IntoIterator<Item = Option<T>>) -> impl Iterator<Item = T> {
it.into_iter().filter_map(|x| x)
}
for n in filter_some(opts) {
}
syntax sugar is like real sugar, if you desire too much of it, it's bad for your health.