キャプチャ
クロージャは柔軟で、型注釈がなくても動きます。これのおかげで、 場合に応じて所有権をもらったり借用したりすることができます。 クロージャは変数を捕捉(キャプチャ)できます。
- 参照として(
&T) - 可変参照として(
&mut T) - 値として(
T)
クロージャははじめ参照を取得しようとし、場合に応じて他のものも取得します。
fn main() { use std::mem; let color = String::from("green"); // `color`を借用(`&`)して出力するクロージャを作り、借用と共に変数 // `print`に保存します。`print`が最後に使われるまで借用は続きます。 // `println!`は不変参照があれば機能するので、これ以上なにかする必要はない。 let print = || println!("`color`: {}", color); // 借用を使ったクロージャを呼び出す。 print(); // クロージャは不変な借用しか保持していないため、 // `color`はもう1度借用できます。 let _reborrow = &color; print(); // `print`の最後の使用のあとでのみ所有権を渡せます。 let _color_moved = color; let mut count = 0; // `count`をインクリメントするクロージャは`&mut count`または`count`を // 必要としますが、`&mut count`で事足りるのでそれを使います。よって // `count`を借用します。 // // 内部に可変な型があるので、`inc`には`mut`が必要です。 // 可変なクロージャは呼び出す度に内部変数を変更します。 let mut inc = || { count += 1; println!("`count`: {}", count); }; // 可変借用を使ったクロージャを呼ぶ。 inc(); // あとで呼び出されるため、クロージャはまだ`count`を可変借用しています。 // なので、もう1度借用とするとエラーになります。 // let _reborrow = &count; // ^ TODO: この行をアンコメントしてみてください。 inc(); // クロージャはもう使われないので、`&mut count`を借用する必要はありません。 // なので、エラーなく再借用できます。 let _count_reborrowed = &mut count; // コピーできない型 let movable = Box::new(3); // `mem::drop`は`T`を必要とするので、値そのものが必要である。 // コピーできる型はコピーし、できない型は値をそのまま移動させます。 let consume = || { println!("`movable`: {:?}", movable); mem::drop(movable); }; // `consume`は変数を消費するため、一度しか呼べません。 consume(); // consume(); // ^ TODO: この行をアンコメントしてみてください。 }
バーティカルバー(|)の前にmoveを付けると、キャプチャした変数の
所有権をもらいます。
fn main() { // `Vec`はコピーできない型です。 let haystack = vec![1, 2, 3]; let contains = move |needle| haystack.contains(needle); println!("{}", contains(&1)); println!("{}", contains(&4)); // println!("There're {} elements in vec", haystack.len()); // ^ ボローチェッカーは移動させた後の変数の再利用を禁止しているので、 // 上をアンコメントすると、コンパイルエラーになります。 // `move`をクロージャから削除すると、クロージャは変数haystackを不変借用するので、 // haystackはまだ使え、上をアンコメントしてもエラーしなくなります。 }