Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

入力パラメーターとして

Rust は、ほとんど型注釈なしで、その場で変数をどのようにキャプチャするかを選択しますが、関数を書く際にはこの曖昧さは許されません。 入力パラメーターとしてクロージャを受け取る場合、クロージャの完全な型は、いくつかの traits のいずれかを使用して注釈付けする必要があり、それらはクロージャがキャプチャした値に対して何を行うかによって決まります。 制約が強い順に、次のとおりです。

  • Fn: クロージャはキャプチャした値を参照(&T)で使用します
  • FnMut: クロージャはキャプチャした値を可変参照(&mut T)で使用します
  • FnOnce: クロージャはキャプチャした値を値(T)で使用します

コンパイラーは、変数ごとに、可能な限り最も制約の少ない方法で変数をキャプチャします。

たとえば、FnOnce と注釈付けされたパラメーターについて考えてみましょう。これは、クロージャが &T&mut T、または T でキャプチャする_可能性がある_ことを指定しますが、最終的にはコンパイラーが、キャプチャされた変数がクロージャ内でどのように使用されるかに基づいて選択します。

これは、ムーブが可能であれば、どの種類の借用も可能であるはずだからです。逆は成り立たないことに注意してください。パラメーターが Fn と注釈付けされている場合、&mut T または T による変数のキャプチャは許可されません。ただし、&T は許可されます。

次の例では、FnFnMutFnOnce の使用を入れ替えて、何が起こるか試してみてください。

// クロージャを引数として受け取り、それを呼び出す関数。
// <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));
}

関連項目:

std::mem::dropFnFnMutジェネリクスwhere、および FnOnce