到達点は、借用と所有権の違いを保ちながら、抽出と集計を書くことです。前提は第08・09回です。
取り出し方で所有関係が変わる
Vecに対するiterは共有参照、iter_mutは可変参照、into_iterはVecを消費して所有する要素を取り出す使い方ができます。同じ「繰り返し」に見えても、元のデータを後で使えるかが違います。
fn main() {
let mut values = vec![10, 20, 30];
let threshold = 15;
let total: i32 = values.iter()
.copied()
.filter(|value| *value >= threshold)
.sum();
println!("{total}");
for value in values.iter_mut() { *value += 1; }
let labels: Vec<String> = values.into_iter()
.enumerate()
.map(|(index, value)| format!("{}: {value}", index + 1))
.collect();
println!("{:?}", labels);
}
src/main.rsでの出力は50、11・21・31に番号を付けたリストです。copiedはCopyできる値を参照から取り出します。filterは判定のため要素を借りるので、ここでは引数を参照外しして比較しています。
クロージャは周囲の値を使える
縦棒で囲んだ引数の後ろがクロージャの本体です。例のfilterは周囲のthresholdを使います。クロージャは使い方に応じて共有借用、可変借用、所有権の取得を行います。Fn、FnMut、FnOnceは、どう呼び出せるかを表すトレイトです。
moveを付けると捕捉する値をクロージャへ移しますが、moveだから必ず一回しか呼べないわけではありません。中で所有物を消費するかなどが関係します。呼び出し方と捕捉方法を区別します。
mapなどは遅延して処理され、collect、sum、forなどで消費して初めて進みます。副作用をmapへ隠すより、変換はmap、明示的な操作はforというように読み手へ意図を示します。
練習と解答
練習:into_iterの後にvaluesを表示できない理由と、元のVecを残す修正を説明します。
解答:今回のinto_iterはVecを消費するためです。values.iter() で借用し、必要なCopy値はcopiedで取り出すか、参照を使って表示文字列を作ります。全部cloneする前に、借用で足りるか考えましょう。
公式資料
Rust全20回の目次 | 前の回 | 次の回