Rustでよくわからずに for ループを使っていたらますますわからないことが増えてきたので、ちゃんとした使い方を調べた。
よくわからずに使用した例
ループをさせたい場合 for-in が利用できる:
fn main() { |
この書式は他の動的スクリプティング言語とパッと見たところ同じ:
# Python |
なので、同じように使えるのかと思ってしまう。 しかし実際にはだいぶ違うので、同じアナロジーで理解しているとハマることになる。
ハマリポイント1:配列で使えない
ベクトルが使えるんだから配列も同じように使えるだろうと推測してしまうんだけど、できない:
fn main() { |
error[E0277]: `[{integer}; 3]` is not an iterator |
エラーメッセージの通り、 &array とスライスにするか、 .iter() としてやる必要がある。
ハマリポイント2:スライスやiter()の値を渡そうとするとエラーが出る
上記の続きでスライスや .iter() を使ってもループ変数 x は println! で普通に表示されているので要素型なのかと思ってしまうが、違う:
fn for_array2() { |
error[E0308]: mismatched types |
エラーメッセージの通り、 *x としてやる必要がある。
ハマリポイント3:ベクトルが移動されてしまう
ベクトルを for に与えると移動されてしまって、その後は使用できない:
fn main() { |
error[E0382]: borrow of moved value: `v` |
続けて使用できるようにするにはスライスや参照を渡せばよい。
forループはなんなのか?
for-in にベクトルは与えられるけど配列は与えられないというのはどういうことなのか、
どういう場合に使えるのか?
ドキュメントのfor Loops and IntoIterator を読むと、
for ループはシンタックスシュガーで
IntoIteratorトレイトを実装している型に対して使える、とのこと。
(なぜベクトルは IntoIterator トレイトが実装されているのに、配列にないのかというのが謎だが…)
同じページ内の上部、反復の3形式によると、
iter(),&Tで反復iter_mut(),&mut Tで反復into_iter(),Tで反復
ということを把握しておくと理解しやすいように思う。
forループ、イテレータ使用のイディオム
内容更新
.iter_mut() を使うとループ変数に &mut T が入ってくるので、更新できる:
let mut array = [1, 2, 3]; |
イテレーション中にも更新できるというのがポイント。
イテレータで使えるメソッド
Iteratorトレイトにはいろいろメソッドが用意されているので、メソッドをつなげていわゆる map や filter などいろいろなメソッドを使える。
その中でもよく使いそうなものの一部を列挙:
- map: 値の変換
- filter: 条件に合う要素を取り出す
- fold: 畳み込み
- count: 個数
- enumerate: イテレーションが何番目かというのを加える
- position: 条件に合う要素のインデクスを返す
- all: 全要素が条件を満たすか?
- any: 1つでも条件を満たすか?
- collect: イテレータをコレクションに変換
他、多数…。
結論
- 基本的には移動はさせたくない場合が多いと思うので、
.iter()の参照イテレータを使用する - 更新する場合には
.iter_mut() .into_iter()だと移動が発生する(ので基本的には使わないでしょう)