Rust日本語公式ドキュメントのIteratorの解説を読むと、Iteratorは一度しか使えないというニュアンスを受ける。
つまり、このコードはイテレータを消費、または使い込むのです。 nextの各呼び出しは、イテレータの要素を一つ、食います。
食べたら無くなるということは、抽象的なイテレータを受け取る関数はそのイテレータを一度しか使えないと考えるかもしれない。しかしFilterやMapなどを多用しても要素がCloneトレイトを実装している場合はそのIteratorもclone()を呼び出せるため、clone()によりイテレーターを巻き戻すことができる。このことを利用して循環イテレーターを生成するcycle()などが実装されている。
以下に0から20までのRangeにMapを適用したイテレーターを受けとり、イテレーターを巻き戻しながら素数の倍数を出力する関数の例を示す
fn main() {
reuse_iterator((0..20).map(|v| v as i32))
}
fn reuse_iterator(vec: impl Iterator<Item=i32> + Clone){
for div in [3,5,7,11]{
print!("multiple of {:>2} are",div);
for i in vec.clone().filter(|v| {
if (*v)%div==0{
true
}else{
print!("* ");//イテレーターが怠惰であることを確認
false
}
}){
print!("{:>2}",i);
}
println!();
}
}
出力
イテレーターが怠惰であること、イテレーターを消費した後もCloneにより再使用できていることを示す
multiple of 3 are 0* * 3* * 6* * 9* * 12* * 15* * 18*
multiple of 5 are 0* * * * 5* * * * 10* * * * 15* * * *
multiple of 7 are 0* * * * * * 7* * * * * * 14* * * * *
multiple of 11 are 0* * * * * * * * * * 11* * * * * * * *