Rustにおいてクロージャは、外部スコープの変数を「キャプチャ」できる匿名関数です。構文は次の通りです:
let add = |a: i32, b: i32| a + b;
Rustには3種類のクロージャがあります(変数のキャプチャ方法によって異なります):
&T)をキャプチャし、環境をミュータブルにせずに何度でも呼び出すことができます。&mut T)をキャプチャし、呼び出し時にクロージャ内のデータを変更できます。T)。Rustは必要なタイプを自動的に判断しますが、明示的に指定することもできます。
違いの例:
let s = String::from("hello"); // FnOnce let consume = move || println!("{}", s); // sは呼び出し後にアクセスできなくなります
なぜmoveキーワードを持つクロージャはFnOnceではなくFnまたはFnMutになることがあるのですか?
回答: moveキーワードは所有権による変数のキャプチャを移動しますが、クロージャ内部のデータがミュータブルでなく、破壊されない場合、クロージャはFn/FnMutと互換性を保ちます。例えば:
let s = String::from("abc"); let c = move || println!("String: {}", s); // c: impl Fn() c();
cは何度でも呼び出すことができます:値sはクロージャにコピーされ、破壊されていません。
物語
データストリームプロジェクトの初心者Rust開発者が、
moveなしでクロージャを書こうとし、別のスレッドに渡した結果、コンパイラーがoutlived borrowに対して文句を言い、ライフタイムやmoveの微妙な点を急いで理解する羽目になりました。
物語
クロージャ内でミュータビリティを導入したが、タイプをFnMutに変更せず、その結果iteratorを使用するすべての場所で「mismatched types」が発生しました。
物語
大きな配列を処理する際、クロージャが全コレクションをmoveで奪い、無意識に所有権を移動させてしまい、外部コードが最初のイテレーション後にデータにアクセスできなくなり、moved valueにアクセスしようとすることになりました。