Conditionally iterate over one of several possible iterators
The either crate provides the Either
type. If both halves of Either
are iterators, then so is the Either
:
extern crate either;
use either::Either;
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
let iter = match x {
None => Either::Left(1..5),
Some(x) => Either::Right(iter::repeat(x).take(5)),
};
for i in iter {
println!("{}", i);
}
}
Like a previous answer, this still takes stack space for each concrete type you have. However, you don't need individual variables for each concrete value.
This type can also be returned from a function, unlike the trait object references. Compared to boxed trait objects, it will always use a fixed size on the stack, regardless of which concrete type was chosen.
You'll find this type (or semantic equivalent) in other places as well, such as futures::Either
The most straightforward solution is to use a trait object:
use std::iter;
fn main() {
let mut a;
let mut b;
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
let iter: &mut dyn Iterator<Item = i64> = match x {
None => {
a = 1..5;
&mut a
}
Some(x) => {
b = iter::repeat(x).take(5);
&mut b
}
};
for i in iter {
println!("{}", i);
}
}
The main downside for this solution is that you have to allocate stack space for each concrete type you have. This also means variables for each type. A good thing is that only the used type needs to be initialized.
The same idea but requiring heap allocation is to use boxed trait objects:
use std::iter;
fn main() {
let x: Option<i64> = None;
// Repeat x 5 times if present, otherwise count from 1 to 5
let iter: Box<dyn Iterator<Item = i64>> = match x {
None => Box::new(1..5),
Some(x) => Box::new(iter::repeat(x).take(5)),
};
for i in iter {
println!("{}", i);
}
}
This is mostly useful when you want to return the iterator from a function. The stack space taken is a single pointer, and only the needed heap space will be allocated.
You can also use an enum for each possible concrete iterator.