第28回です。前回はこちら。
[第28回の様子]
2022/02/09に第28回を開催した。
内容としてはRust By Example 日本語版の「9.2.4. 関数を受け取る関数」、「9.2.5. クロージャを返す関数」、「9.2.6. stdにおける使用例」に取り組んだ。
しばらく続いていたクロージャのシリーズがこれでひと段落。
参加者は7人。安定して5人以上参加者がいて嬉しい😄
ちなみに、今回の範囲(と前々回あたりの範囲)がまだ翻訳されていなかったので、Rust dojoのメンバーがプルリクを出してくれていた。
今回の未翻訳の箇所はこちらを見ながら進められたので、とても助かった。
[学んだこと]
- 9.2.4. 関数を受け取る関数
- 前回が、クロージャを受け取る関数だったので、関数を受け取るもいけるよね、って話
- こんなかんじでいける
fn call_me<F: Fn()>(f: F) {
f();
}
fn function() {
println!("I'm a function!");
}
fn main() {
let closure = || println!("I'm a closure!");
call_me(closure); // I'm a closure!
call_me(function); // I'm a function!
}
- ちなみに、関数の引数や戻り値の型指定は、こんなかんじでいける
fn call_me_with_args<F: Fn(i32) -> i32>(f: F) -> i32 {
f(2)
}
fn function_with_args(n: i32) -> i32 {
println!("I'm a function! {}", n);
n + 1
}
fn main() {
let closure_with_args = |n: i32| {
println!("I'm a closure! {}", n);
n + 1
};
let c_res = call_me_with_args(closure_with_args); // I'm a closure! 2
println!("c_res {}", c_res); // c_res 3
let f_res = call_me_with_args(function_with_args); // I'm a function! 2
println!("f_res {}", f_res); // f_res 3
}
- 9.2.5. クロージャを返す関数
- クロージャを関数の戻り値にすることもできる
- その場合の型指定は
impl Trait(TraitはFnとかFnMut)
fn create_fn() -> impl Fn() {
let text = "Fn".to_owned();
move || println!("This is a: {}", text)
}
fn main() {
let fn_plain = create_fn();
fn_plain(); // This is a: Fn
}
fn create_fn2(n: i32) -> impl Fn() {
let text = "Fn".to_owned();
move || println!("This is a: {} {}", text, n)
}
fn main() {
let fn_plain2= create_fn2(2);
fn_plain2(); // This is a: Fn 2
}
- 9.2.6. stdにおける使用例
- クロージャの使い方として、stdライブラリを見ていく
- まずは
Iterator::any:シグネチャはこうなっている
pub trait Iterator { // イテレートされる値の型 type Item; fn any<F>(&mut self, f: F) -> bool where // FnMutなので、クロージャによって補足される変数が変更されるが、 // FnOnceではないので、メモリが解放されるわけではない F: FnMut(Self::Item) -> bool {} // FnMutの引数がSelf::Itemなので、参照ではなく値として取る }
- 使い方はこのようになる
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// ベクトル型に対する`iter`は`&i32`を返す
println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2)); // 2 in vec1: true
// `into_iter()`の場合は`i32`を返す
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2)); // 2 in vec2: false
}
Iterator::findの例も載っていた- こちらはクロージャの引数が値ではなく参照となる点が
Iterator::anyと異なる
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`を返す
let mut iter = vec1.iter();
// `inter_iter()`の場合は`i32`を返す
let mut into_iter = vec2.into_iter();
// &i32のリファレンスは`&&i32`となる
println!("Find 2 in vec1: {:?}", iter .find(|&&x| x == 2)); // Find 2 in vec1: Some(2)
// `into_iter`の場合は`&i32`が要素の参照
println!("Find 2 in vec2: {:?}", into_iter.find(| &x| x == 2)); // Find 2 in vec2: None
Iterator::findは要素そのものを返すので、インデックスが必要ならIterator::positionを使う
fn main() {
let vec = vec![1, 9, 3, 3, 13, 2];
let index_of_first_even_number = vec.iter().position(|x| x % 2 == 0);
pritnln!("{:?}", index_of_first_even_number); // Some(5)
}
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
先週までの蓄積があったので、今週の内容は比較的簡単に理解できた気がする!
今週のプルリクエストはこちら。