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

Rustってどんな言語

unisuke
November 20, 2022

 Rustってどんな言語

unisuke

November 20, 2022
Tweet

More Decks by unisuke

Other Decks in Technology

Transcript

  1. Rustってどんな言語

  2. Rustが目指すのはいいとこ取り っっっっっk 低レベルの制御 メモリ安全性 C, C++.. Python, JavaScript… Rust

  3. C++が安全でなくてRustが安全 っっっっっk っっs 1 std::vector<int> v { 10, 11 };

    2 int *vptr = &v[1]; 3 v.push_back(12); 4 std::cout << *vptr; C++
  4. C++が安全でなくてRustが安全 っっっっっk っっs 1 std::vector<int> v { 10, 11 };

    2 int *vptr = &v[1]; 3 v.push_back(12); 4 std::cout << *vptr; C++ Bug (use-after-free) result
  5. C++が安全でなくてRustが安全 っっっっっk 10 11 v 1 std::vector<int> v { 10,

    11 }; 2 int *vptr = &v[1]; 3 v.push_back(12); 4 std::cout << *vptr; C++
  6. C++が安全でなくてRustが安全 っっっっっk 10 11 v 1 std::vector<int> v { 10,

    11 }; 2 int *vptr = &v[1]; 3 v.push_back(12); 4 std::cout << *vptr; C++ vptr
  7. C++が安全でなくてRustが安全 っっっっっk 10 11 v 1 std::vector<int> v { 10,

    11 }; 2 int *vptr = &v[1]; 3 v.push_back(12); 4 std::cout << *vptr; C++ vptr 10 11 v 12
  8. C++が安全でなくてRustが安全 っっっっっk 10 11 v 1 std::vector<int> v { 10,

    11 }; 2 int *vptr = &v[1]; 3 v.push_back(12); 4 std::cout << *vptr; C++ vptr すでに解放済みのメモリ をさしている →ダングリングポインタ
  9. C++が安全でなくてRustが安全 っっっっっk っっs 1 let mut v = vec![10, 11];

    2 let vptr = &mut v[1]; 3 v.push(12); 4 println!("{}", *vptr); Rust
  10. C++が安全でなくてRustが安全 っっっっっk っっs 1 let mut v = vec![10, 11];

    2 let vptr = &mut v[1]; 3 v.push(12); 4 println!("{}", *vptr); Rust コンパイルエラー result
  11. 所有権システム っっっっっk • メモリはコンパイラがコンパイル時にチェックする一定の規則とともに 所有権システムを通じて管理されている • Rustの各値は、所有者と呼ばれる変数と対応している。 • いかなる時も所有者は一つである。 •

    所有者がスコープから外れたら、値は破棄される。 所有権の原則
  12. 所有権システム っっっっっk let s1 = String::from("hello"); let s2 = s1;

    println!("s2 = {}", s2); //println!("s1 = {}", s1); Rust “hello” s1 所有者 • Rustの各値は、所有者と呼ばれる変数と対応している。 所有権の原則
  13. 所有権システム っっっっっk let s1 = String::from("hello"); let s2 = s1;

    println!("s2 = {}", s2); //println!("s1 = {}", s1); Rust “hello” s1 • いかなる時も所有者は一つである。 所有権の原則 s2 所有者
  14. 所有権システム っっっっっk let s1 = String::from("hello"); let s2 = s1;

    println!("s2 = {}", s2); //println!("s1 = {}", s1); Rust “hello” s1 s2 所有者 s2 = hello result
  15. 所有権システム っっっっっk let s1 = String::from("hello"); let s2 = s1;

    println!("s2 = {}", s2); println!("s1 = {}", s1); Rust “hello” s1 s2 所有者 コンパイルエラー(s1: value borrowed here after move) result
  16. 所有権システムのメリット っっっっっk • メモリに起因する問題を克服し てメモリ安全性が保証される • 解放忘れ/二重解放のトラブル がなくなる • 脆弱性の原因になる挙動を避け

    られる(ex. ダングリングポイ ンタ) vs 手動でメモリ管理 • ガベージコレクタの実行速度の 遅さ、メモリ効率というデメリ ットを克服する • 効率的で高速 vs ガベージコレクタ
  17. 所有権と関数 っっっっっk fn main() { let s1 = String::from("hello"); show_str(s1);

    println!("s1 = {}", s1); } fn show_str(str: String) { println!("{}", str); } Rust “hello” s1 str 所有者
  18. 所有権と関数 っっっっっk fn show_message(str: String) { println!("{}", str); } Rust

    “hello” s1 • 所有者がスコープから外れたら、値は破棄される。 所有権の原則 str 所有者 変数strがスコープ抜ける スコープ抜ける 破棄
  19. 所有権と関数 っっっっっk fn main() { let s1 = String::from("hello"); show_str(s1);

    println!("s1 = {}", s1); } Rust “hello” s1 破棄 コンパイルエラー(s1: value borrowed here after move) result
  20. 関数に渡した値を呼び出し元で再度使いたいとき① っっっっっk fn main() { let mut s1 = String::from("hello");

    s1 = show_str(s1); println!("s1 = {}", s1); } fn show_str(str: String) -> String { println!("{}", str); str } Rust “hello” s1 str 所有者
  21. 関数に渡した値を呼び出し元で再度使いたいとき① っっっっっk fn main() { let mut s1 = String::from("hello");

    s1 = show_str(s1); println!("s1 = {}", s1); } fn show_str(str: String) -> String { println!("{}", str); str } Rust “hello” s1 str 所有者
  22. 関数に渡した値を呼び出し元で再度使いたいとき① っっっっっk fn main() { let mut s1 = String::from("hello");

    s1 = show_str(s1); println!("s1 = {}", s1); } fn show_str(str: String) -> String { println!("{}", str); str } Rust s1 = hello result
  23. 共有参照 っっっっっk • 与えた値を参照する参照を生成することができる • 値を参照するだけで、所有はしない • 関数の引数に参照を取ることを借用と呼ぶ • データへの一時的なアクセスを許し、操作的にはポインタに相当する

    • 複製が可能 • 共有参照が存在する場合、所有者も値の変更ができない &[変数名 / 値] ex. &s1, &String::from("hello") 記法
  24. 関数に渡した値を呼び出し元で再度使いたいとき② っっっっっk fn main() { let s1 = String::from("hello"); show_str(&s1);

    println!("s1 = {}", s1); } fn show_str(str: &String) { println!("{}", str); } Rust “hello” s1 所有者
  25. 関数に渡した値を呼び出し元で再度使いたいとき② っっっっっk fn main() { let s1 = String::from("hello"); show_str(&s1);

    println!("s1 = {}", s1); } fn show_str(str: &String) { println!("{}", str); } Rust “hello” s1 str 所有者 s1の値を参照 所有権の移動は 発生しない
  26. 関数に渡した値を呼び出し元で再度使いたいとき② っっっっっk fn show_str(str: &String) { println!("{}", str); } Rust

    “hello” s1 str 所有者 s1の値を参照 所有権の移動は 発生しない 変数strがスコープ抜けるが、strは所有権を持た ないため、値は破棄されない
  27. 関数に渡した値を呼び出し元で再度使いたいとき② っっっっっk fn main() { let s1 = String::from("hello"); show_str(&s1);

    println!("s1 = {}", s1); } fn show_str(str: &String) { println!("{}", str); } Rust s1 = hello result
  28. 値を変更したいときは所有権持たせるしかない。。? っっっっっk fn main() { let s1 = String::from("hello"); show_str(&s1);

    println!("s1 = {}", s1); } fn show_str(str: &String) { str.push_str(" sample"); println!("{}", str); } Rust コンパイルエラー `str` is a `&` reference, so the data it refers to cannot be borrowed as mutable result
  29. 可変参照 っっっっっk • 可変な参照を生成する • 値を参照するだけで、所有はしない &mut [変数名 / 値]

    ex. &mut s1 記法
  30. 関数内で値を変更 っっっっっk fn main() { let mut s1 = String::from("hello");

    show_str(&mut s1); println!("s1 = {}", s1); } fn show_str(str: &mut String) { str.push_str(" sample"); println!("{}", str); } Rust hello sample s1 = hello sample result
  31. 可変参照 っっっっっk • 特定のスコープで、ある特定のデータに対しては、 一つしか可変な参 照を持てない • 不変な参照をしている間は、可変な参照をすることはできない 制約 1.

    2つ以上のポインタが同じデータに同時にアクセスする 2. 少なくとも一つのポインタがデータに書き込みを行っている 3. データへのアクセスを同期する機構が使用されていない データ競合が起こる条件 データ競合 を防ぐこと ができる
  32. ライフタイム っっっっっk • 全ての参照に有効時間が設定されている • 参照の完全な形は参照型の完全な形は &'a mut Tまたは &'a

    Tで、'a は参照の有効期限、ライフタイムを省略できる規約もいくつかある
  33. C++が安全でなくてRustが安全 っっっっっk っっs 1 let mut v = vec![10, 11];

    2 let vptr = &mut v[1]; 3 v.push(12); 4 println!("{}", *vptr); Rust コンパイルエラー result
  34. ダングリングポインタをコンパイルエラーで防ぐ っっっっっk っっs fn sample() { let mut data: Vec<i32>

    = vec![10, 11]; // ↓ let vptr = &mut v[1]; let vptr : &'b i32 = Index::index::<'b>(&'b data, 0); // ↓ v.push(12); Vec::push(&'c mut data, 4) println!("{}", x); } Rust
  35. ダングリングポインタをコンパイルエラーで防ぐ っっっっっk っっs fn sample() { 1 let mut data:

    Vec<i32> = vec![10, 11]; 2 let x: &'b i32 = Index::index::<'b>(&'b data, 0); 3 Vec::push(&'c mut data, 4); 4 println!("{}", x); } Rust --------+'a | ----+'b | +'c | | ----+ | --------+
  36. ダングリングポインタをコンパイルエラーで防ぐ っっっっっk っっs fn sample() { 1 let mut data:

    Vec<i32> = vec![10, 11]; 2 let x: &'b i32 = Index::index::<'b>(&'b data, 0); 3 Vec::push(&'c mut data, 4); 4 println!("{}", x); } Rust --------+'a | ----+'b | +'c | | ----+ | --------+ xは'bで生存しなくてはいけない
  37. ダングリングポインタをコンパイルエラーで防ぐ っっっっっk っっs fn sample() { 1 let mut data:

    Vec<i32> = vec![10, 11]; 2 let x: &'b i32 = Index::index::<'b>(&'b data, 0); 3 Vec::push(&'c mut data, 4); 4 println!("{}", x); } Rust --------+'a | ----+’b | | | +‘c | | ----+ | --------+ xは'bで生存しなくてはいけない dataを参照する参照が’bで生存することを要求する
  38. 可変参照 っっっっっk • 特定のスコープで、ある特定のデータに対しては、 一つしか可変な参 照を持てない • 不変な参照をしている間は、可変な参照をすることはできない 制約 1.

    2つ以上のポインタが同じデータに同時にアクセスする 2. 少なくとも一つのポインタがデータに書き込みを行っている 3. データへのアクセスを同期する機構が使用されていない データ競合が起こる条件 データ競合 を防ぐこと ができる
  39. ダングリングポインタをコンパイルエラーで防ぐ っっっっっk っっs 不変な参照をしている間に可変な参照をすることはできないのでエラー fn sample() { 1 let mut

    data: Vec<i32> = vec![10, 11]; 2 let x: &'b i32 = Index::index::<'b>(&'b data, 0); 3 Vec::push(&'c mut data, 4); 4 println!("{}", x); } Rust --------+'a | ----+’b | | | +‘c | | ----+ | --------+ xは'bで生存しなくてはいけない dataを参照する参照が’bで生存することを要求する 新しい可変参照を生成⚠
  40. unsafe Rust っっっっっk • コンピュータのハードウェアが本質的にunsafeであるため、unsafeな処理 ができないと、特定の制御ができない • デバッグのため、unsafeブロックを小さくすることを推奨している • 生ポインタを参照外しすること

    • unsafeな関数やメソッドを呼ぶこと • 可変で静的な変数にアクセスしたり変更すること • unsafeなトレイトを実装すること unsafe superpowers(safe Rustでは行えない4つの行動)