
Rustのイテレータはコレクション操作の救世主!効率的なデータ処理でコードをスッキリさせよう🚀
Rustのイテレータとは?基本と仕組み
Rustにおけるイテレータは、一連の値を順番に処理するための強力な仕組みです。コレクション(例えばVec、HashMapなど)の要素を一つずつ取り出す際に非常に役立ちます。イテレータを使うことで、ループ処理をより安全かつ効率的に記述できます。
イテレータはIteratorトレイトを実装した構造体であり、next()メソッドを提供します。next()メソッドは、次の要素をOption<T>型で返します。要素が存在する場合はSome(T)、終端に達した場合はNoneを返します。
rust
let v = vec![1, 2, 3];
let mut iter = v.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), None);
この例では、v.iter()でベクタvのイテレータを作成しています。iter.next()を呼び出すことで、ベクタの要素が順番に取り出され、最後にNoneが返されます。
イテレータの便利なメソッド集
Rustのイテレータは、様々な便利なメソッドを提供しています。これにより、要素のフィルタリング、変換、集計などが簡潔に行えます。ここでは、特によく使われるメソッドを紹介します。
map()メソッドは、イテレータの各要素に関数を適用し、新しいイテレータを生成します。
rust
let v = vec![1, 2, 3];
let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();
assert_eq!(doubled, vec![2, 4, 6]);
この例では、各要素を2倍にするmap()を使用しています。.collect()は、イテレータの結果をコレクション(ここではVec<i32>)に変換します。
filter()メソッドは、指定された条件を満たす要素のみを含む新しいイテレータを生成します。
rust
let v = vec![1, 2, 3, 4, 5, 6];
let even: Vec<i32> = v.iter().filter(|x| x % 2 == 0).cloned().collect();
assert_eq!(even, vec![2, 4, 6]);
ここでは、偶数のみを抽出するfilter()を使用しています。.cloned()は、参照をコピーに変換するために使用します。
collect()メソッドは、イテレータの要素をコレクション(Vec, HashMap, Stringなど)に変換します。
rust
let v = vec![1, 2, 3];
let string: String = v.iter().map(|x| x.to_string()).collect();
assert_eq!(string, "123");
ここでは、数値を文字列に変換し、それらを連結して一つのStringを生成しています。
fold()メソッドは、イテレータの要素を累積して単一の値にします。
rust
let v = vec![1, 2, 3, 4];
let sum = v.iter().fold(0, |acc, x| acc + x);
assert_eq!(sum, 10);
この例では、fold()を使用してベクタの要素の合計を計算しています。最初の引数0は初期値、2番目の引数は累積関数です。
any()メソッドは、イテレータの少なくとも一つの要素が条件を満たすかどうかを判定します。all()メソッドは、すべての要素が条件を満たすかどうかを判定します。
rust
let v = vec![1, 2, 3, 4, 5];
let has_even = v.iter().any(|x| x % 2 == 0);
let all_positive = v.iter().all(|x| x > &0);
assert_eq!(has_even, true);
assert_eq!(all_positive, true);
イテレータと所有権
Rustのイテレータは所有権と密接に関連しています。iter()、iter_mut()、into_iter()の3種類のイテレータがあり、それぞれが異なる所有権の扱いをします。
iter(): 不変な参照を生成します。元のコレクションは変更されません。
iter_mut(): 可変な参照を生成します。元のコレクションを変更できます。
into_iter(): 所有権をムーブします。元のコレクションはイテレータに消費されます。
rust
let v = vec![1, 2, 3];
// iter()
for x in v.iter() { // vの不変な参照
println!("{}", x);
}
println!("{:?}", v); // vは有効
// into_iter()
let mut v2 = vec![1,2,3];
for x in v2.into_iter() { // v2の所有権がmoveされる
println!("{}", x);
}
//println!("{:?}", v2); // v2はもう有効ではないので、コンパイルエラー
into_iter()を使用すると、イテレータがベクタの所有権を奪うため、その後のベクタへのアクセスはコンパイルエラーになります。
参考リンク
まとめ
Rustのイテレータは、コレクションを効率的に処理するための強力なツールです。map()、filter()、collect()、fold()などの便利なメソッドを活用することで、簡潔で読みやすいコードを書くことができます。所有権の概念を理解し、iter()、iter_mut()、into_iter()を適切に使い分けることで、安全かつ効率的なイテレータ処理を実現できます。ぜひRustのイテレータを使いこなして、より高度なプログラミングに挑戦してください。

