Rustのクロージャ(無名関数)基礎と使い方

先生

Rustのクロージャは強力な武器!匿名関数でコードをスマートに。

Rustのクロージャとは?基本概念をわかりやすく解説

Rustにおけるクロージャは、別名「無名関数」とも呼ばれ、名前を持たない関数として定義できます。クロージャは、定義されたスコープ内の変数をキャプチャできるため、柔軟で強力なプログラミングを可能にします。JavaScriptのクロージャと同様の概念ですが、Rustでは所有権と借用のルールに基づいて、より安全に動作します。

クロージャは、関数ポインタ、関数オブジェクト(trait)、そしてクロージャそのものの3つの型として扱うことができます。この柔軟性により、様々な状況で最適なパフォーマンスと安全性を提供します。

クロージャは||で引数を囲み、{}で処理を囲みます。引数がない場合は|| {}となります。単一の式の場合は{}を省略できます。

let add_one = |x: i32| x + 1;
println!("{}", add_one(5)); // 出力: 6

クロージャの構文と定義方法

Rustのクロージャは非常に簡潔に記述できます。基本的な構文は以下の通りです。

|引数| -> 返り値の型 { 処理内容 }

引数の型推論が可能な場合は、型を省略できます。また、戻り値の型も推論できる場合は省略可能です。

let add = |x, y| x + y; // 型推論によりi32と推定される
println!("{}", add(2, 3)); // 出力: 5

複数の処理を行う場合は、{}で囲みます。

let process = |x: i32| {
    let y = x * 2;
    y + 1
};

クロージャは変数に代入して使用するのが一般的ですが、直接呼び出すことも可能です。

(|x: i32| x * x)(5); // 出力は返り値として破棄される

クロージャによる変数のキャプチャ:ムーブと借用

クロージャの最も強力な機能の一つは、周囲のスコープから変数をキャプチャできることです。Rustでは、キャプチャの方法は3種類あります。

1. 借用(&T): クロージャは変数を参照として借用します。クロージャが終了するまで、元の変数は有効である必要があります。

let x = 10;
let print_x = || println!("x: {}", x); // xを借用
print_x(); // x: 10

2. 可変借用(&mut T): クロージャは変数を可変参照として借用します。クロージャ内で変数の値を変更できます。

let mut x = 10;
let mut increment_x = || x += 1; // xを可変借用
increment_x();
println!("x: {}", x); // x: 11

3. ムーブ(move): クロージャは変数の所有権を移動させます。クロージャ内で変数のコピーではなく、元の変数が使用されます。moveキーワードを使用します。

let x = String::from("hello");
let print_x = move || println!("x: {}", x); // xの所有権をムーブ
print_x(); // x: hello
// println!("{}", x); // エラー! xは既にムーブされている

moveキーワードは、特にスレッド間でデータを安全に共有する場合に重要になります。

クロージャの活用例:イテレータと高階関数

クロージャは、イテレータと組み合わせて使用することで、コレクションの操作を簡潔に記述できます。mapfilterfoldなどの高階関数は、クロージャを引数として受け取ります。

let numbers = vec![1, 2, 3, 4, 5];
let squared_numbers: Vec<_> = numbers.iter().map(|x| x * x).collect();
println!("{:?}", squared_numbers); // 出力: [1, 4, 9, 16, 25]

filterを使って偶数のみを抽出する例:

let even_numbers: Vec<_> = numbers.iter().filter(|x| x % 2 == 0).collect();
println!("{:?}", even_numbers); // 出力: [2, 4]

foldを使って合計を計算する例:

let sum = numbers.iter().fold(0, |acc, x| acc + x);
println!("{}", sum); // 出力: 15

これらの高階関数とクロージャを組み合わせることで、複雑なデータ処理を簡潔に表現できます。

参考リンク

まとめ

Rustのクロージャは、匿名関数として、変数キャプチャの機能を持つ強力なツールです。借用とムーブの概念を理解することで、安全かつ効率的なコードを書くことができます。イテレータや高階関数と組み合わせることで、データ処理をより簡潔に記述できます。Rustのクロージャをマスターして、より表現力豊かなプログラミングを目指しましょう。