MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Rustの基礎 - クロージャのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Rustの基礎 - クロージャ
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == クロージャとは、環境の変数をキャプチャできる無名関数のことを指す。<br> <br> 通常のメソッドとは異なり、定義されたスコープの変数を参照することができる。<br> Rustのクロージャは、型推論が可能で、引数と戻り値の型を明示的に指定する必要がない場合が多い。<br> <br><br> == クロージャの基本 == クロージャを定義する基本的な構文を以下に示す。<br> <syntaxhighlight lang="rust"> let closure_name = |引数| 式; </syntaxhighlight> <br> 以下の例では、2つの引数を受け取り、その合計を返すクロージャを定義している。<br> <syntaxhighlight lang="rust"> fn main() { let add = |a, b| a + b; println!("{}", add(2, 3)); } // 出力 5 </syntaxhighlight> <br> 複数行のクロージャを定義する場合は、波括弧<code>{}</code>を使用する。<br> <syntaxhighlight lang="rust"> fn main() { let add = |a, b| { let result = a + b; result }; println!("{}", add(2, 3)); } // 出力 5 </syntaxhighlight> <br> 型を明示的に指定することもできる。<br> <syntaxhighlight lang="rust"> fn main() { let add = |a: i32, b: i32| -> i32 { a + b }; println!("{}", add(2, 3)); } // 出力 5 </syntaxhighlight> <br><br> == 環境のキャプチャ == クロージャは、定義されたスコープの変数をキャプチャすることができる。<br> これが通常のメソッドとの主な違いである。<br> <syntaxhighlight lang="rust"> fn main() { let x = 10; let add_x = |y| x + y; println!("{}", add_x(5)); } // 出力 15 </syntaxhighlight> <br> クロージャは、変数を3つの方法でキャプチャできる。<br> * 不変参照 (<code>&T</code>) によるキャプチャ * 可変参照 (<code>&mut T</code>) によるキャプチャ * 所有権の移動 (<code>T</code>) によるキャプチャ <br> デフォルトでは、クロージャは必要最小限の方法で変数をキャプチャする。<br> <syntaxhighlight lang="rust"> fn main() { let mut count = 0; // 可変参照でキャプチャ let mut increment = || { count += 1; println!("count: {}", count); }; increment(); increment(); } // 出力 count: 1 count: 2 </syntaxhighlight> <br><br> == メソッドがクロージャを返す == 以下の例では、outer_funcメソッドがクロージャを返している。<br> このクロージャは、outer_funcメソッドの引数aとbをキャプチャしている。<br> <syntaxhighlight lang="rust"> fn outer_func(a: i32, b: i32) -> impl Fn() -> i32 { move || a + b } fn main() { let result = outer_func(2, 3); println!("{}", result()); } // 出力 5 </syntaxhighlight> <br> 上記の例では、<code>move</code> キーワードを使用している。<br> これは、クロージャが変数の所有権を奪うことを明示的に指定している。<br> <br> <code>move</code>を使用しないと、クロージャは参照でキャプチャしようとするが、<br> メソッドから返される場合は、ライフタイムの問題が発生するため、<code>move</code> キーワードが必要となる。<br> <br> 戻り値の型impl Fn() -> i32は、引数を取らずi32を返すクロージャを意味する。<br> <br><br> == クロージャの実行 == クロージャを実行するには、変数に代入した後、関数と同様に丸括弧 <code>()</code> を使用する。<br> <syntaxhighlight lang="rust"> fn outer_func(a: i32, b: i32) -> impl Fn() -> i32 { move || a + b } fn main() { let func = outer_func(2, 3); println!("{}", func()); } // 出力 5 </syntaxhighlight> <br> 以下の例では、長方形の面積を計算している。<br> 引数に横(width)を与えるarea_calc メソッドを定義して、縦(height)を引数として面積を計算するクロージャを返している。<br> <syntaxhighlight lang="rust"> fn area_calc(width: i32) -> impl Fn(i32) -> i32 { move |height| width * height } fn main() { // widthが25と50の場合を計算 let ac1 = area_calc(25); let ac2 = area_calc(50); // heightを10として面積を求める println!("{}", ac1(10)); println!("{}", ac2(10)); } // 出力 250 500 </syntaxhighlight> <br><br> == クロージャのトレイト == Rustのクロージャは、以下に示す3つのトレイトのいずれかを実装する。<br> * <code>FnOnce</code> *: 1度だけ呼び出せるクロージャ。 *: キャプチャした変数の所有権を消費する可能性がある。 * <code>FnMut</code> *: 複数回呼び出せるクロージャ。 *: キャプチャした変数を可変的に借用する。 * <code>Fn</code> *: 複数回呼び出せるクロージャ。 *: キャプチャした変数を不変的に借用する。 <br> 全てのクロージャは少なくとも <code>FnOnce</code> を実装する。<br> キャプチャした変数を消費しないクロージャは <code>FnMut</code> も実装する。<br> キャプチャした変数を変更しないクロージャは <code>Fn</code> も実装する。<br> <br> 以下の例では、それぞれのトレイトを使用したクロージャを示している。<br> <syntaxhighlight lang="rust"> fn main() { // Fn : 不変借用 let x = 5; let print_x = || println!("x = {}", x); print_x(); print_x(); // 複数回呼び出せる // FnMut : 可変借用 let mut count = 0; let mut increment = || { count += 1; count }; println!("{}", increment()); println!("{}", increment()); // 複数回呼び出せる // FnOnce: 所有権の移動 let s = String::from("hello"); let consume = || { drop(s); // sの所有権を消費 }; consume(); // consume(); // エラー: 2回目は呼び出せない } // 出力 x = 5 x = 5 1 2 </syntaxhighlight> <br><br> == メソッドの引数としてクロージャを受け取る == メソッドの引数としてクロージャを受け取ることができる。<br> 以下の例では、ジェネリクスとトレイト境界を使用してクロージャを受け取っている。<br> <syntaxhighlight lang="rust"> fn apply<F>(f: F, x: i32, y: i32) -> i32 where F: Fn(i32, i32) -> i32, { f(x, y) } fn main() { let add = |a, b| a + b; let multiply = |a, b| a * b; println!("{}", apply(add, 3, 4)); println!("{}", apply(multiply, 3, 4)); } // 出力 7 12 </syntaxhighlight> <br> <code>impl Trait</code> 構文を使用して、簡潔に記述することもできる。<br> <syntaxhighlight lang="rust"> fn apply(f: impl Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { f(x, y) } fn main() { let add = |a, b| a + b; println!("{}", apply(add, 3, 4)); } // 出力 7 </syntaxhighlight> <br><br> == イテレータとクロージャ == Rustでは、イテレータのメソッドでクロージャを頻繁に使用する。<br> 以下に示すものは、代表的な使用例である。<br> <br> <code>map</code>メソッドを使用して、各要素を変換する例。<br> <syntaxhighlight lang="rust"> fn main() { let numbers = vec![1, 2, 3, 4, 5]; let doubled: Vec<i32> = numbers.iter().map(|&x| x * 2).collect(); println!("{:?}", doubled); } // 出力 [2, 4, 6, 8, 10] </syntaxhighlight> <br> 以下の例では、<code>filter</code> メソッドを使用して、条件に合う要素のみを抽出している。<br> <syntaxhighlight lang="rust"> fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; let evens: Vec<i32> = numbers.iter().filter(|&x| x % 2 == 0).copied().collect(); println!("{:?}", evens); } // 出力 [2, 4, 6] </syntaxhighlight> <br> 以下の例では、<code>fold</code> メソッドを使用して、累積計算を行っている。<br> <syntaxhighlight lang="rust"> fn main() { let numbers = vec![1, 2, 3, 4, 5]; let sum = numbers.iter().fold(0, |acc, &x| acc + x); println!("{}", sum); } // 出力 15 </syntaxhighlight> <br><br> == クロージャと所有権 == クロージャは、キャプチャした変数の所有権を扱う方法を柔軟に制御できる。<br> <br> デフォルトでは、クロージャは必要最小限の方法で変数をキャプチャする。<br> <syntaxhighlight lang="rust"> fn main() { let s = String::from("hello"); // 不変参照でキャプチャ let print = || println!("{}", s); print(); // sはまだ使用できる println!("{}", s); } </syntaxhighlight> <br> <code>move</code> キーワードを使用すると、所有権を強制的に移動できる。<br> これは、クロージャが元のスコープよりも長く生存する場合に必要となる。<br> <syntaxhighlight lang="rust"> use std::thread; fn main() { let s = String::from("hello"); // 別スレッドで実行するため、moveが必要 let handle = thread::spawn(move || { println!("{}", s); }); // println!("{}", s); // エラー: sの所有権は移動済み handle.join().unwrap(); } </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:Rust]]
Rustの基礎 - クロージャ
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse