Rust dojo第28回を開催した

第28回です。前回はこちら。

kdnakt.hatenablog.com

 

 

[第28回の様子]

2022/02/09に第28回を開催した。

 

内容としてはRust By Example 日本語版の「9.2.4. 関数を受け取る関数」、「9.2.5. クロージャを返す関数」、「9.2.6. stdにおける使用例」に取り組んだ。

しばらく続いていたクロージャのシリーズがこれでひと段落。

 

参加者は7人。安定して5人以上参加者がいて嬉しい😄

 

ちなみに、今回の範囲(と前々回あたりの範囲)がまだ翻訳されていなかったので、Rust dojoのメンバーがプルリクを出してくれていた。

今回の未翻訳の箇所はこちらを見ながら進められたので、とても助かった。

github.com

 

[学んだこと]

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
}
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
}
  • FnMutでもFnOnceでも大体おなじだが、FnOnceのクロージャを2回呼ぶとコンパイルエラーになるのはこれまで見た通り。
  • クロージャを作るときに、関数の引数を捕捉できる
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
}
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を開催した。

先週までの蓄積があったので、今週の内容は比較的簡単に理解できた気がする!

 

今週のプルリクエストはこちら。

github.com