Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. fn / クロージャ(|x| x+1)

fn / クロージャ(|x| x+1)

Rustの関数は『fn』キーワードで定義します。クロージャは『|引数| 式』の形式で書き、外側の変数をキャプチャできます。クロージャは関数の引数として渡したり変数に代入したりできます。

構文
// 通常の関数定義です。引数型と戻り値型を明示します。
fn add(a: i32, b: i32) -> i32 {
    a + b  // 最後の式が戻り値になります(セミコロンなし)。
}

// クロージャ(無名関数)の定義です。型推論が効くため型を省略できます。
let add = |a, b| a + b;
let double = |x: i32| -> i32 { x * 2 };

// 外側の変数をキャプチャします(借用)。
let offset = 10;
let add_offset = |x| x + offset;  // offsetを借用します。

// move クロージャ:所有権ごとムーブして取り込みます。
let name = String::from("Rust");
let greet = move || println!("Hello, {}", name);  // nameの所有権が移動します。

// 関数の引数としてクロージャを受け取ります(Fn トレイト)。
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
    f(x)
}
関数・クロージャ関連一覧
構文/トレイト概要
fn name(引数) -> 型 { }通常の関数を定義します。
|引数| 式クロージャ(無名関数)を定義します。型は推論されます。
|引数: 型| -> 型 { }型を明示したクロージャです。
move |引数| 式外側の変数の所有権を移動してキャプチャします。
Fn(&self)不変参照でキャプチャするクロージャです。
FnMut(&mut self)可変参照でキャプチャするクロージャです(内部状態を変更)。
FnOnce(self)所有権を移動してキャプチャするクロージャです(1度だけ呼べます)。
fn(型) -> 型関数ポインタ型です(クロージャとは異なります)。
impl Fn(型) -> 型クロージャを返す関数の戻り値型に使います。
サンプルコード
// 高階関数:関数を引数として受け取ります。
fn apply<F>(f: F, values: &[i32]) -> Vec<i32>
where
    F: Fn(i32) -> i32,
{
    values.iter().map(|&x| f(x)).collect()
}

// クロージャを返す関数です。
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
    move |x| x + n  // n の所有権をクロージャにムーブします。
}

fn main() {
    // 通常の関数です。
    fn square(x: i32) -> i32 {
        x * x
    }
    println!("square(5) = {}", square(5));

    // クロージャの基本です。
    let double = |x| x * 2;
    let add_one = |x: i32| -> i32 { x + 1 };
    println!("double(4) = {}", double(4));
    println!("add_one(9) = {}", add_one(9));

    // 外側の変数をキャプチャします。
    let threshold = 5;
    let is_big = |x| x > threshold;  // threshold を借用します。
    println!("is_big(7) = {}", is_big(7));
    println!("is_big(3) = {}", is_big(3));

    // 高階関数にクロージャを渡します。
    let nums = vec![1, 2, 3, 4, 5];
    let doubled = apply(|x| x * 2, &nums);
    println!("doubled: {:?}", doubled);

    let squared = apply(square, &nums);  // 通常の関数も渡せます。
    println!("squared: {:?}", squared);

    // クロージャを返す関数(クロージャファクトリ)です。
    let add5 = make_adder(5);
    let add10 = make_adder(10);
    println!("add5(3) = {}", add5(3));
    println!("add10(3) = {}", add10(3));

    // FnMut:内部状態を変更するクロージャです。
    let mut counter = 0;
    let mut increment = || {
        counter += 1;
        counter
    };
    println!("count: {}", increment());  // 1
    println!("count: {}", increment());  // 2
    println!("count: {}", increment());  // 3
}
概要

Rustのクロージャは外側の変数をキャプチャする方法によって自動的に『Fn』『FnMut』『FnOnce』のいずれかのトレイトを実装します。変数を参照するだけなら『Fn』、変更するなら『FnMut』、所有権を移動するなら『FnOnce』になります。

クロージャを他のスレッドやより長く生きる場所に渡すときは『move』キーワードが必要です。moveを使うとキャプチャした変数の所有権がクロージャ内に移動します。

クロージャが可変参照でキャプチャしている間は、その変数を同時に他の場所で使えません。借用チェッカーのルールが適用されます。

クロージャの詳細なトレイト(Fn/FnMut/FnOnce)は『Fn / FnMut / FnOnce トレイト』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。