Rust dojo第3回を開催した

先週に続いて第3回です。

 

kdnakt.hatenablog.com

 

 

[第3回の様子]

2021/07/28に第3回を開催した。

 

内容としてはRust By Example 日本語版の「1.2.1. デバッグ」と「1.2.2. ディスプレイ」を途中まで読んで手を動かした。

 

参加者はおそらく全部で10人ほど。

先週からガクッと減っているが、今週は弊社の新型コロナワクチン職域摂取2回目が行われており、ダウンしている人が多いことに起因すると思われる。来週はみんな復活してきて欲しい。

かくいう自分も一瞬ダウンして、ブログの公開が遅れてしまった。

 

今回は2回目の参加のメンバーに半ば無理やりドライバーをお願いした。

ときどきRustに詳しいメンバーからチャットでコメントをもらったり、口頭で補足説明をもらえたりしたので、とても助かった。

 

参加人数はいつもより少なかったけど、開催前後のSlackでのやりとりが今回もたくさん🎉

 

開始前からワクチン2回目でダウンした方々から「無理」との反応や欠席連絡が。 

f:id:kidani_a:20210730081351p:plain

f:id:kidani_a:20210730081521p:plain

 

しっかり準備していざ開始、と思ったらGoogle Meetのトラブルも……お騒がせしました🙇‍♂️

f:id:kidani_a:20210730082110p:plain

f:id:kidani_a:20210730081648p:plain

 

終わった後で、ライフタイムやstructについて詳細な解説をいただけたり。

f:id:kidani_a:20210730082416p:plain

f:id:kidani_a:20210730082538p:plain

 

ドライブの感想もいただけた。ありがたや!

f:id:kidani_a:20210730082658p:plain

 

[学んだこと]

  • stdライブラリの型は自動的に{}または{:?}でプリントすることができる
  • stdライブラリではfmt::Displayfmt::Debugのトレイトがそれぞれ実装されているため。
// この構造体は`fmt::Display`、`fmt::Debug`のいずれによっても
// プリントすることができません。
struct UnPrintable(i32);

// `derive`アトリビュートは、
// この構造体を`fmt::Debug`でプリントするための実装を自動で提供します。
#[derive(Debug)]
struct Structure(i32);

#[derive(Debug)]
struct Deep(Structure);

fn main() {
    println!("{:?} months in a year.", 12);
    // 12 months in a year.

    println!("{1:?} {0:?} is the {actor:?} name.",
             "Slater",
             "Christian",
             actor="actor's");
    // "Christian" "Slater" is the "actor's" name.

    println!("Now {:?} will print!", Structure(3));
    // Now Structure(3) will print!
    
    println!("Now {:?} will print!", Deep(Structure(7)));
    // Now Deep(Structure(7)) will print!
  • {:?}ではあまり見栄えが良くないが、解決策が2つある
  • ひとつは、以下のように{:#?}を利用するやり方
#[derive(Debug)]
struct Person<'a> {
    name: &'a str,
    age: u8
}

fn main() {
    let name = "Peter";
    let age = 27;
    let peter = Person { name, age };

    // Pretty print
    println!("{:#?}", peter);
}
  • 上記の出力結果は以下のようになる
Person {
    name: "Peter",
    age: 27,
}
  • ここで、初めての記法が出てきた:'aというライフタイムに関する部分だ
  • str型のnameのライフタイムとPerson型のライフタイムを揃えるためにこのように書く必要があるらしい
  • u8型のageの方になぜそれが必要ないのかはいまいちわからなかった:多分そのうちわかるだろう...
  • ageの方にもライフタイムを設定すると以下のようになるらしい
#[derive(Debug)]
struct Person<'a> {
    name: &'a str,
    age: &'a u8
}

fn main() {
    let name = "Peter";
    let age = 27;
// 引数とフィールドの型が一致しないのでこのような書き方になる let peter = Person { name, age: &age }; // Pretty print println!("{:#?}", peter); }
  • もうひとつの見栄えをよくする方法が、fmt::Displayを手動で実装すること
use std::fmt;

struct Structure(i32);

impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0) // 0番目のフィールドを出力する
    }
}

fn main() {
    println!("{}", Structure(28));
    // 28
}
  • 実験してみたところ、これは深い階層のstructでもうまく機能した
struct Deep(Structure);

fn main() {
    println!("Now {} will print!", Deep(Structure(7)));
    // Now 7 will print!
}

use std::fmt;

struct Structure(i32);

impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl fmt::Display for Deep {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}
  • この実験で、fn main()で利用するstructが後から定義されていてもうまく動くことに気がついた。まあそれはそうか...
  • fmt::Displayは以上のように綺麗な出力を得られる:一方で、曖昧な型の場合に問題がある
  • Vec<T>のようなコレクションの出力で、Vec<path>Vec<number>は異なるセパレータを利用したいはずだ
  • このような場合にはfmt::Debugを利用すべき

 

[まとめ]

モブプログラミングスタイルでRust dojoをやった!

fmt::Displayトレイトを実装する方法を学んだ!

 

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

github.com