Slide 1

Slide 1 text

© Money Forward, Inc. 簡単なシェルを作って Rustを学ぼう🦀 TaKO8Ki 2022/10/27 Rustハンズオンイベント

Slide 2

Slide 2 text

© Money Forward, Inc. ● A member of Rust compiler team contributors ● Love OSS ● Live in Kyoto I’m TaKO8Ki. GitHub: @TaKO8Ki

Slide 3

Slide 3 text

© Money Forward, Inc. はじめに

Slide 4

Slide 4 text

© Money Forward, Inc. はじめに 2時間弱のイベントなので、 自由に寝そべったり、好みの姿勢を取った り、ふらっとトイレに行ったりしていただ いて問題ないです!

Slide 5

Slide 5 text

© Money Forward, Inc. はじめに CommentScreenを使ってコメントできます


Slide 6

Slide 6 text

© Money Forward, Inc. はじめに https://commentscreen.com/comments?room=rust-hands-on QRコードはしばらくスライドの端に載せておきます room nameは「rust-hands-on」 CommentScreenを使ってコメントできます

Slide 7

Slide 7 text

© Money Forward, Inc. Table of Contents ● 今日作るもの ● Rustの基本的なところ ● ハンズオン 🦀 rust-hands-on

Slide 8

Slide 8 text

© Money Forward, Inc. 今日作るもの

Slide 9

Slide 9 text

© Money Forward, Inc. 今日作るもの

Slide 10

Slide 10 text

© Money Forward, Inc. Rustの基本的なとこ ろ

Slide 11

Slide 11 text

© Money Forward, Inc. Rustの基本的なところ まだRustを書いたことがない人は、 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh https://www.rust-lang.org/tools/install rust-hands-on

Slide 12

Slide 12 text

© Money Forward, Inc. Rustの基本的なところ 使いそうなツール
 # Build $ cargo build # Lint $ cargo clippy # Format $ cargo fmt rust-hands-on

Slide 13

Slide 13 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ LSPを使うなら、 RustのためのLSP実装。IDE用のRustコンパイラフロントエ ンド。 VSCodeならExtensionを入れるだけ。 https://rust-analyzer.github.io/manual.html#installation

Slide 14

Slide 14 text

© Money Forward, Inc. Rustのどこが難しいと思いま すか?

Slide 15

Slide 15 text

© Money Forward, Inc. 所有権?

Slide 16

Slide 16 text

© Money Forward, Inc. borrow checker?

Slide 17

Slide 17 text

© Money Forward, Inc. lifetime?

Slide 18

Slide 18 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ メモリマネジメントの手法 ● 手動でメモリ管理する ● Garbage collection

Slide 19

Slide 19 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ メモリマネジメント ● 手動でメモリ管理する ● Garbage collection ● RAII - Resource Acquisition Is Initialization > 日本語では「リソース取得は初期化である」「リソースの確保は初期化時に」 「リソースの取得と初期化」などの意味を持ち、資源(リソース)の確保と解放 を、クラス型の変数の初期化と破棄処理に結び付けるというプログラミングのテク ニックである。 https://ja.wikipedia.org/wiki/RAII

Slide 20

Slide 20 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ Rustのメモリマネジメント Rustは、所有権と借用によってエイリアシングとミューテーションの両方 が同時に起こらないことを保証している。

Slide 21

Slide 21 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ let s = String::new(); 所有権(ownership)とは? ● 新しいオブジェクトを作ると、代入された変数はそのオブジェクトの オーナーになる。 ● いかなる時もオーナーは一つだけ。 ● オーナーがスコープを抜けたらオブジェクトはドロップされる。

Slide 22

Slide 22 text

© Money Forward, Inc. Rustの基本的なところ 所有権(ownership)とは? fn main() { let a = String::new("foo"); let b = s; println!("{}", a); } rust-hands-on

Slide 23

Slide 23 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 所有権(ownership)とは? error[E0382]: borrow of moved value: `s` --> src/main.rs:4:20 | 2 | let s = String::new(); | - move occurs because `s` has type `String`, which does not implement the `Copy` trait 3 | let p = s; | - value moved here 4 | println!("{}", s); | ^ value borrowed here after move |

Slide 24

Slide 24 text

© Money Forward, Inc. Rustの基本的なところ 所有権(ownership)とは? fn main() { let a = String::new("foo"); let b = s; // bが新しいオーナー println!("{}", a); } rust-hands-on

Slide 25

Slide 25 text

© Money Forward, Inc. Rustの基本的なところ 所有権(ownership)とは? fn main() { let a = String::new("hello"); let b = s; // bが新しいオーナー println!("{}", a); // moveされた値を使っているのでエラー } メモリの二重解放を防ぐことができる。 rust-hands-on

Slide 26

Slide 26 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ moveが起こらないケース fn main() { let a: u32 = 3; let b = a; // コピー println!("{}", a); } Copy Traitが実装されている型はmoveが起こらず値がコピーされる。

Slide 27

Slide 27 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 所有権(ownership)とは? Copy Traitが実装されている型の一部: ● 整数型 (u32など) ● bool ● 浮動小数点型 (f64) ● char。 ● Copyの型だけを含むタプル。 例えば、(i32, i32) はこれに含まれるが、 (i32, String) は含まれない。

Slide 28

Slide 28 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 借用(borrow)とは? fn main() { let a = String::from("hello"); let b = &a; a.len(); b.len(); }

Slide 29

Slide 29 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 借用(borrow)とは? fn main() { let a = String::from("hello"); let b = &a; let c = &a; // 複数借用することも可能 a.len(); b.len(); c.len(); }

Slide 30

Slide 30 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 借用(borrow)とは? fn main() { let a: &Vec; { let b = Vec::new(); a = &b; } // bはここでドロップされる a.len(); // オーナーbがドロップされているのでエラー } エイリアスは可能だが参照はオブジェクトより長生きできない

Slide 31

Slide 31 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 借用(borrow)とは? error[E0597]: `b` does not live long enough --> src/main.rs:5:13 | 5 | a = &b; | ^^ borrowed value does not live long enough 6 | } //v is dropped here | - `b` dropped here while still borrowed 7 | a.len(); //error:borrowed value does not live long enough | ------- borrow later used here

Slide 32

Slide 32 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ ミュータブルな借用 fn main() { let mut a = String::from("hello"); let b = &mut a; // 1つ目のミュータブルな参照 let c = &mut a; // 2つ目のミュータブルな参照 b.push_str("a"); // cannot borrow `a` as mutable more than once at a time } ミュータブルな参照は一度に一つだけ。

Slide 33

Slide 33 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ ミュータブルな借用 fn main() { let mut a = vec![0, 1, 2, 3]; let b = &a[0]; // vecの最初の要素へのイミュータブルな参照 a.clear(); let c = *b; // 無効なメモリにアクセスする可能性がある } イミュータブル、ミュータブルな参照が同時に可能だと、

Slide 34

Slide 34 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ ライフタイム fn main() { let r; // ---------+-- 'a // | { // | let x = 5; // -+-- 'b | r = &x; // | | } // -+ | // | println!("r: {}", r); // | } // ---------+ 全ての参照はライフタイムを持っている。 bがaより小さい

Slide 35

Slide 35 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ ライフタイム fn main() { let x = 5; // ----------+-- 'b // | let r = &x; // --+-- 'a | // | | println!("r: {}", r); // | | // --+ | } // ----------+ コンパイルを通すには、 bがaより大きくなった

Slide 36

Slide 36 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn main() { let string1 = String::from("abcd"); let string2 = "xyz"; let result = longest(string1.as_str(), string2); println!("The longest string is {}", result); } 長い方のStringを返すような関数を書いたとする。

Slide 37

Slide 37 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x } else { y } } 長い方のStringを返すような関数を書いたとする。

Slide 38

Slide 38 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム 下記のようにコンパイルエラーになる。 error[E0106]: missing lifetime specifier --> src/main.rs:9:33 | 9 | fn longest(x: &str, y: &str) -> &str { | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | 9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { | ++++ ++ ++ ++

Slide 39

Slide 39 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x } else { y } } コンパイラはx、yどちらが返り 値になるか分からないので返り 値のライフタイムが有効かも分 からない

Slide 40

Slide 40 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム error[E0106]: missing lifetime specifier --> src/main.rs:9:33 | 9 | fn longest(x: &str, y: &str) -> &str { | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` help: consider introducing a named lifetime parameter | 9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { | ++++ ++ ++ ++

Slide 41

Slide 41 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } 引数と返り値にライフタイムをコンパイラに教えてやる。

Slide 42

Slide 42 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ ライフタイム注釈 &Vec // 参照 &'a Vec // ライフタイムを明示した参照 &'a mut Vec // ライフタイムを明示したミュータブルな参照 この注釈は「少なくともライフタイム 'aと同じだけ生きる」ということを意味している。

Slide 43

Slide 43 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn main() { let string1 = String::from("long string is long" ); { let string2 = String::from("xyz"); let result = longest(string1.as_str(), string2.as_str()); println!("The longest string is {}", result); } // string2、resultはここまで生きる } // string1 はここまで生きる コンパイルできる例

Slide 44

Slide 44 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn main() { let string1 = String::from("long string is long" ); let result; { let string2 = String::from("xyz"); result = longest(string1.as_str(), string2 .as_str()); } // string2はここまで生きる println!("The longest string is {}", result); } // string1、resultはここまで生きる コンパイルできない例 返り値のライフタイムは引数の内小さい方のもの(string2のライフタイム)と同じと解釈される

Slide 45

Slide 45 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム コンパイルできない例 error[E0597]: `string2` does not live long enough --> src/main.rs:6:44 | 6 | result = longest(string1.as_str(), string2.as_str()); | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough 7 | } | - `string2` dropped here while still borrowed 8 | println!("The longest string is {}", result); | ------ borrow later used here

Slide 46

Slide 46 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ Structへのライフタイム注釈 struct ImportantExcerpt<'a> { part: &'a str, }

Slide 47

Slide 47 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ Methodへのライフタイム注釈 impl<'a> ImportantExcerpt<'a> { fn level(&self) -> i32 { 3 } }

Slide 48

Slide 48 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ Staticなライフタイム let s: &'static str = "I have a static lifetime." ; 特別なライフタイムとして、'staticがある。 これは、その参照がプログラムが終了するまで生き続けることを示している。 static NUM: i32 = 18; 'staticライフタイムを注釈して定数を定義する。

Slide 49

Slide 49 text

© Money Forward, Inc. rust-hands-on Rustの基本的なところ staticとconst static FOO: &str = "foo"; const BAR: i32 = 10; ● const: 不変な値 ● static: 'staticライフタイムを持つ変更可能な値。mutableな物へのアクセスや 変更はunsafeです。

Slide 50

Slide 50 text

© Money Forward, Inc. ハンズオン 🦀

Slide 51

Slide 51 text

© Money Forward, Inc. rust-hands-on ハンズオン 🦀 雛形を作ろう PRに沿って実装していく用のRepository(途中まで): https://github.com/TaKO8Ki/smash 完全版Repository: https://github.com/TaKO8Ki/toy-shell ※ 自分もシェル初心者なのでバグやら実装ミスやらあればissue投げてい ただけるとありがたいです。(toy-shellの方へ)

Slide 52

Slide 52 text

© Money Forward, Inc. rust-hands-on ハンズオン 🦀 雛形を作ろう $ cargo new # crate作る # first commit見てmain.rsとConfig.tomlをコピペ。CI回す場合 は、.github/workflows/ci.ymlも $ cargo run # 実行 $ RUST_LOG=smash::event=debug cargo run $ cargo test # #[test] cfg(test)

Slide 53

Slide 53 text

© Money Forward, Inc. rust-hands-on ハンズオン 🦀 多分ここまでが限界 - Implement exit https://github.com/TaKO8Ki/smash/pull/7 - Visit simple command https://github.com/TaKO8Ki/smash/pull/6

Slide 54

Slide 54 text

© Money Forward, Inc. 参考 ● HashRust - experieance the joy of Rust https://hashrust.com ● Validating References with Lifetimes https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html ● constants - Rust By Example https://doc.rust-lang.org/rust-by-example/custom_types/constants.html ● A command-line shell like fish, but POSIX compatible. https://github.com/nuta/nsh

Slide 55

Slide 55 text

No content