Rust dojo第20回を開催した

第20回です。

前回はこちら。

kdnakt.hatenablog.com

 

 

[第20回の様子]

2021/12/01に第20回を開催した。

 

内容としてはRust By Example 日本語版の「8.3. while」、「8.4. for と range」に取り組んだ。

 

参加者は、ちょっと減って、7人だった。

 

[学んだこと]

  • 8.3. while
  • 無限ループを作るloopと違って、カウンタを使うwhileも書ける
  • FizzBuzzをwhileを使って書くとこうなる
fn main() {
    // カウンタとなる変数
    let mut n = 1;

    // `n`が101以下である場合のループ
    while n < 101 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }

        // カウンタに1を追加
        n += 1;
    }
}
  • loopではbreak 戻り値;の形式でloopから値を返すことができたので、whileでも試してみる
fn main() {
    let _ret = while n < 101 {
        if n % 15 == 0 {
            println!("fizzbuzz");
            break n;
        } else if n % 3 == 0 {
        ...
    }
}

// 以下のコンパイルエラー
error[E0571]: `break` with value from a `while` loop
  --> src/main.rs:11:13
   |
8  |     let _ret = while n < 101 {
   |                ------------- you can't `break` with a value in a `while` loop
...
11 |             break n;
   |             ^^^^^^^ can only break with a value inside `loop` or breakable block
   |
help: use `break` on its own without a value inside this `while` loop
   |
11 |             break;
   |             ~~~~~
  • break;でブレークすることはできるけど、値を返せるのはloopのみ、と言われてしまった。無念。
  • 8.4. for と range
  • forの条件式としてrangeを用いる方法は2つある
for n in 1..101 {
    // 1〜100まで
}

for n in 1..=100 {
    // 1〜100まで
}
  • for in構文では3種類のイテレータを使うことができる
  • 1つ目は.iter()
fn main() {
    let names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter() {
        match name {
            &"Ferris" => println!("There is a rustacean among us!"),
            _ => println!("Hello {}", name),
        }
    }
    println!("{:?}", names);
}
  • これはコレクションの要素を借用するので、
  • 2つ目は.into_iter()
fn main() {
    let names = vec!["Bob", "Frank", "Ferris"];

    for name in names.into_iter() {
        match name {
            "Ferris" => println!("There is a rustacean among us!"),
            _ => println!("Hello {}", name),
        }
    }
}
  • こちらのやり方の場合、データがループ内に移動するため、matchの方法も参照(&)ではなくなっている
  • 移動したデータは使えなくなるため、先ほどのようにprintln!をfor文のあとに追加すると以下のコンパイルエラーとなってしまう
error[E0382]: borrow of moved value: `names`
   --> src/main.rs:11:22
    |
2   |     let names = vec!["Bob", "Frank", "Ferris"];
    |         ----- move occurs because `names` has type `Vec<&str>`, which does not implement the `Copy` trait
3   | 
4   |     for name in names.into_iter() {
    |                       ----------- `names` moved due to this method call
...
11  |     println!("{:?}", names);
    |                      ^^^^^ value borrowed here after move
    |
note: this function takes ownership of the receiver `self`, which moves `names`
  • 3つ目は.iter_mut()
  • これを使うと、コレクション内のデータを変更できる
fn main() {
    let mut names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter_mut() {
        *name = match name {
            &mut "Ferris" => "There is a rustacean among us!",
            _ => "Hello",
        }
    }

    println!("names: {:?}", names); // forループ後の再利用も問題ない
}

 

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。

基本的なループのforとwhileがやっと出てきた!イテレータだけで何個もパターンがあって覚えられない...。

 

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

github.com