入力パラメーターとして
Rust は、ほとんど型注釈なしで、その場で変数をどのようにキャプチャするかを選択しますが、関数を書く際にはこの曖昧さは許されません。 入力パラメーターとしてクロージャを受け取る場合、クロージャの完全な型は、いくつかの traits のいずれかを使用して注釈付けする必要があり、それらはクロージャがキャプチャした値に対して何を行うかによって決まります。 制約が強い順に、次のとおりです。
Fn: クロージャはキャプチャした値を参照(&T)で使用しますFnMut: クロージャはキャプチャした値を可変参照(&mut T)で使用しますFnOnce: クロージャはキャプチャした値を値(T)で使用します
コンパイラーは、変数ごとに、可能な限り最も制約の少ない方法で変数をキャプチャします。
たとえば、FnOnce と注釈付けされたパラメーターについて考えてみましょう。これは、クロージャが &T、&mut T、または T でキャプチャする_可能性がある_ことを指定しますが、最終的にはコンパイラーが、キャプチャされた変数がクロージャ内でどのように使用されるかに基づいて選択します。
これは、ムーブが可能であれば、どの種類の借用も可能であるはずだからです。逆は成り立たないことに注意してください。パラメーターが Fn と注釈付けされている場合、&mut T または T による変数のキャプチャは許可されません。ただし、&T は許可されます。
次の例では、Fn、FnMut、FnOnce の使用を入れ替えて、何が起こるか試してみてください。
// クロージャを引数として受け取り、それを呼び出す関数。 // <F> は F が「ジェネリック型パラメーター」であることを示します fn apply<F>(f: F) where // クロージャは入力を受け取らず、何も返しません。 F: FnOnce() { // ^ TODO: これを `Fn` または `FnMut` に変更してみてください。 f(); } // クロージャを受け取り、`i32` を返す関数。 fn apply_to_3<F>(f: F) -> i32 where // クロージャは `i32` を受け取り、`i32` を返します。 F: Fn(i32) -> i32 { f(3) } fn main() { use std::mem; let greeting = "hello"; // コピーではない型。 // `to_owned` は借用されたデータから所有されたデータを作成します let mut farewell = "goodbye".to_owned(); // 2 つの変数をキャプチャします: `greeting` は参照で、 // `farewell` は値でキャプチャされます。 let diary = || { // `greeting` は参照です: `Fn` が必要です。 println!("I said {}.", greeting); // ミューテーションにより、`farewell` は // 可変参照でキャプチャされます。これで `FnMut` が必要になります。 farewell.push_str("!!!"); println!("Then I screamed {}.", farewell); println!("Now I can sleep. zzzzz"); // drop を手動で呼び出すと、`farewell` は // 値でキャプチャされます。これで `FnOnce` が必要になります。 mem::drop(farewell); }; // クロージャを適用する関数を呼び出します。 apply(diary); // `double` は `apply_to_3` のトレイト境界を満たします let double = |x| 2 * x; println!("3 doubled: {}", apply_to_3(double)); }