Upgrade to Pro — share decks privately, control downloads, hide ads and more …

簡単なシェルを作ってRustを学ぼう

TaKO8Ki
November 08, 2022

 簡単なシェルを作ってRustを学ぼう

TaKO8Ki

November 08, 2022
Tweet

More Decks by TaKO8Ki

Other Decks in Programming

Transcript

  1. © Money Forward, Inc. • A member of Rust compiler

    team contributors • Love OSS • Live in Kyoto I’m TaKO8Ki. GitHub: @TaKO8Ki
  2. © Money Forward, Inc. Table of Contents • 今日作るもの •

    Rustの基本的なところ • ハンズオン 🦀 rust-hands-on
  3. © 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
  4. © Money Forward, Inc. Rustの基本的なところ 使いそうなツール
 # Build $ cargo

    build # Lint $ cargo clippy # Format $ cargo fmt rust-hands-on
  5. © Money Forward, Inc. rust-hands-on Rustの基本的なところ メモリマネジメント • 手動でメモリ管理する •

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

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

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

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

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

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

    整数型 (u32など) • bool • 浮動小数点型 (f64) • char。 • Copyの型だけを含むタプル。 例えば、(i32, i32) はこれに含まれるが、 (i32, String) は含まれない。
  13. © 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(); }
  14. © Money Forward, Inc. rust-hands-on Rustの基本的なところ 借用(borrow)とは? fn main() {

    let a: &Vec<i32>; { let b = Vec::new(); a = &b; } // bはここでドロップされる a.len(); // オーナーbがドロップされているのでエラー } エイリアスは可能だが参照はオブジェクトより長生きできない
  15. © 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
  16. © 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 } ミュータブルな参照は一度に一つだけ。
  17. © 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; // 無効なメモリにアクセスする可能性がある } イミュータブル、ミュータブルな参照が同時に可能だと、
  18. © Money Forward, Inc. rust-hands-on Rustの基本的なところ ライフタイム fn main() {

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

    let x = 5; // ----------+-- 'b // | let r = &x; // --+-- 'a | // | | println!("r: {}", r); // | | // --+ | } // ----------+ コンパイルを通すには、 bがaより大きくなった
  20. © 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を返すような関数を書いたとする。
  21. © Money Forward, Inc. rust-hands-on Rustの基本的なところ 関数に対するライフタイム fn longest(x: &str,

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

    y: &str) -> &str { if x.len() > y.len() { x } else { y } } コンパイラはx、yどちらが返り 値になるか分からないので返り 値のライフタイムが有効かも分 からない
  24. © 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 { | ++++ ++ ++ ++
  25. © 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 } } 引数と返り値にライフタイムをコンパイラに教えてやる。
  26. © Money Forward, Inc. rust-hands-on Rustの基本的なところ ライフタイム注釈 &Vec<i32> // 参照

    &'a Vec<i32> // ライフタイムを明示した参照 &'a mut Vec<i32> // ライフタイムを明示したミュータブルな参照 この注釈は「少なくともライフタイム 'aと同じだけ生きる」ということを意味している。
  27. © 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 はここまで生きる コンパイルできる例
  28. © 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のライフタイム)と同じと解釈される
  29. © 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
  30. © Money Forward, Inc. rust-hands-on Rustの基本的なところ Staticなライフタイム let s: &'static

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

    = "foo"; const BAR: i32 = 10; • const: 不変な値 • static: 'staticライフタイムを持つ変更可能な値。mutableな物へのアクセスや 変更はunsafeです。
  32. © Money Forward, Inc. rust-hands-on ハンズオン 🦀 雛形を作ろう PRに沿って実装していく用のRepository(途中まで): https://github.com/TaKO8Ki/smash

    完全版Repository: https://github.com/TaKO8Ki/toy-shell ※ 自分もシェル初心者なのでバグやら実装ミスやらあればissue投げてい ただけるとありがたいです。(toy-shellの方へ)
  33. © 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)
  34. © 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
  35. © 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