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ってどんな言語

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  11. 所有権システム
    っっっっっk
    • メモリはコンパイラがコンパイル時にチェックする一定の規則とともに
    所有権システムを通じて管理されている
    • Rustの各値は、所有者と呼ばれる変数と対応している。
    • いかなる時も所有者は一つである。
    • 所有者がスコープから外れたら、値は破棄される。
    所有権の原則

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  16. 所有権システムのメリット
    っっっっっk
    • メモリに起因する問題を克服し
    てメモリ安全性が保証される
    • 解放忘れ/二重解放のトラブル
    がなくなる
    • 脆弱性の原因になる挙動を避け
    られる(ex. ダングリングポイ
    ンタ)
    vs 手動でメモリ管理
    • ガベージコレクタの実行速度の
    遅さ、メモリ効率というデメリ
    ットを克服する
    • 効率的で高速
    vs ガベージコレクタ

    View Slide

  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
    所有者

    View Slide

  18. 所有権と関数
    っっっっっk
    fn show_message(str: String) {
    println!("{}", str);
    }
    Rust
    “hello”
    s1
    • 所有者がスコープから外れたら、値は破棄される。
    所有権の原則
    str
    所有者
    変数strがスコープ抜ける
    スコープ抜ける
    破棄

    View Slide

  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

    View Slide

  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
    所有者

    View Slide

  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
    所有者

    View Slide

  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

    View Slide

  23. 共有参照
    っっっっっk
    • 与えた値を参照する参照を生成することができる
    • 値を参照するだけで、所有はしない
    • 関数の引数に参照を取ることを借用と呼ぶ
    • データへの一時的なアクセスを許し、操作的にはポインタに相当する
    • 複製が可能
    • 共有参照が存在する場合、所有者も値の変更ができない
    &[変数名 / 値]
    ex. &s1, &String::from("hello")
    記法

    View Slide

  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
    所有者

    View Slide

  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の値を参照
    所有権の移動は
    発生しない

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  29. 可変参照
    っっっっっk
    • 可変な参照を生成する
    • 値を参照するだけで、所有はしない
    &mut [変数名 / 値]
    ex. &mut s1
    記法

    View Slide

  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

    View Slide

  31. 可変参照
    っっっっっk
    • 特定のスコープで、ある特定のデータに対しては、 一つしか可変な参
    照を持てない
    • 不変な参照をしている間は、可変な参照をすることはできない
    制約
    1. 2つ以上のポインタが同じデータに同時にアクセスする
    2. 少なくとも一つのポインタがデータに書き込みを行っている
    3. データへのアクセスを同期する機構が使用されていない
    データ競合が起こる条件
    データ競合
    を防ぐこと
    ができる

    View Slide

  32. ライフタイム
    っっっっっk
    • 全ての参照に有効時間が設定されている
    • 参照の完全な形は参照型の完全な形は &'a mut Tまたは &'a Tで、'a
    は参照の有効期限、ライフタイムを省略できる規約もいくつかある

    View Slide

  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

    View Slide

  34. ダングリングポインタをコンパイルエラーで防ぐ
    っっっっっk
    っっs
    fn sample() {
    let mut data: Vec = 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

    View Slide

  35. ダングリングポインタをコンパイルエラーで防ぐ
    っっっっっk
    っっs
    fn sample() {
    1 let mut data: Vec = 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 | |
    ----+ |
    --------+

    View Slide

  36. ダングリングポインタをコンパイルエラーで防ぐ
    っっっっっk
    っっs
    fn sample() {
    1 let mut data: Vec = 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で生存しなくてはいけない

    View Slide

  37. ダングリングポインタをコンパイルエラーで防ぐ
    っっっっっk
    っっs
    fn sample() {
    1 let mut data: Vec = 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で生存することを要求する

    View Slide

  38. 可変参照
    っっっっっk
    • 特定のスコープで、ある特定のデータに対しては、 一つしか可変な参
    照を持てない
    • 不変な参照をしている間は、可変な参照をすることはできない
    制約
    1. 2つ以上のポインタが同じデータに同時にアクセスする
    2. 少なくとも一つのポインタがデータに書き込みを行っている
    3. データへのアクセスを同期する機構が使用されていない
    データ競合が起こる条件
    データ競合
    を防ぐこと
    ができる

    View Slide

  39. ダングリングポインタをコンパイルエラーで防ぐ
    っっっっっk
    っっs
    不変な参照をしている間に可変な参照をすることはできないのでエラー
    fn sample() {
    1 let mut data: Vec = 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で生存することを要求する
    新しい可変参照を生成⚠

    View Slide

  40. unsafe Rust
    っっっっっk
    • コンピュータのハードウェアが本質的にunsafeであるため、unsafeな処理
    ができないと、特定の制御ができない
    • デバッグのため、unsafeブロックを小さくすることを推奨している
    • 生ポインタを参照外しすること
    • unsafeな関数やメソッドを呼ぶこと
    • 可変で静的な変数にアクセスしたり変更すること
    • unsafeなトレイトを実装すること
    unsafe superpowers(safe Rustでは行えない4つの行動)

    View Slide