Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reading note #2

Open
iterable-company opened this issue Jul 30, 2022 · 11 comments
Open

Reading note #2

iterable-company opened this issue Jul 30, 2022 · 11 comments

Comments

@iterable-company
Copy link
Owner Author

初期値を与えない変数

Rustにはnull値がないということと初期値を与えないことについて矛盾するように感じるかもしれないが、
値を代入する前に変数を参照しようとするとコンパイラエラーとなる。
参照する前に値を代入していれば問題ない!

@iterable-company
Copy link
Owner Author

なぜこれがコンパイルエラーにならないのか?

struct Excerpt<'a> {
    idx: usize,
    part: &'a str,
}

fn main() {
    let mut excerpt1 = Excerpt {
        idx: 1,
        part: "second sentence",
    };
    {
        let str = "changed";
        excerpt1.part = str;
    }
    println!("{:?}", excerpt1); 
}

https://doc.rust-jp.rs/book-ja/ch10-03-lifetime-syntax.html
「この注釈は、ImportantExcerptのインスタンスが、 partフィールドに保持している参照よりも長生きしないことを意味します。」
とあるので、Excerptのインスタンスがpartフィールドの参照より長生きしているこのコードがOKなのはなぜ??

@iterable-company
Copy link
Owner Author

ライフタイム注釈がコンパイラで勝手にふられる場合

  1. 複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが&selfや&mut selfだったら、 selfのライフタイムが全出力ライフタイム引数に代入される

引数がselfより短いライフタイムを持つことを許容しない?
その場合は、ライフタイム注釈をつけるということ?
全引数がselfと同じ場合は、敢えてつけなくてもコンパイラが勝手につけるということ?

@iterable-company
Copy link
Owner Author

iterable-company commented Aug 27, 2022

テストのコマンドラインオプション

cargo test に対するオプションと、ビルドされたテストバイナリに対するオプションがある。
前者は
cargo test
の後にオプションをつける。
後者は
cargo test --
の後にオプションをつける。

ヘルプの出力も
cargo test --helpcargo test -- --helpに分かれている。

@iterable-company
Copy link
Owner Author

モジュール、クレート、パッケージ、ワークスペース

https://doc.rust-jp.rs/book-ja/ch07-01-packages-and-crates.html
https://qiita.com/kerupani129/items/bd41d8a07daa31256aab

モジュール

モジュールは mod {} で囲んで記述できる。
(モジュール自体がどのような意味を持つのかはわからないが、コードのまとまりとして扱う目的の模様)

パッケージ

パッケージは複数のクレートを持てる。
 ライブラリクレートは 0 or 1個
 バイナリクレートは複数可能
パッケージはCargo.toml を持ち、そこでクレート群をどのようにビルドするかを記載している。
パッケージはsrc/bin以下にファイルを置くことで複数のバイナリクレートを持つことができる。
crate.ioに公開されているのはこのパッケージ単位。

ワークスペース

ワークスペースはメンバーとなるパッケージを持ち、それを定義するCargo.tomlを持つ。
パッケージとは別にワークスペースのCargo.tomlがある場合と、パッケージのCargo.tomlにワークスペース用の記述が追加される場合がある。

[workspace]
members = ["foo", "bar", "baz"]
default-members = ["foo"]

ワークスペースでは、 -p でパッケージを指定して実行できる。

cargo run -p foo-package

クレートの指定でも可能

cargo run --bin foo-binary-crate

何も指定しない場合はデフォルトパッケージが実行される。

cargo run

@iterable-company
Copy link
Owner Author

バイナリを crate.ioからインストール

インストールできるのはバイナリターゲットを持つクレート(main.rsを持つ)
通常 $HOME/.cargo/bin に格納される

@iterable-company
Copy link
Owner Author

スマートポインタ

String、Vec などヒープに確保されて、可変なものは基本的にスマートポインタ。
スマートポインタは通常、構造体を使用して実装されているが、通常の構造体との違いは、スマートポインタがDeref, Dropトレイトを実装していること。
Deref トレイトにより、参照のように振る舞うことができる。
Drop トレイトにより、スマートポインタのインスタンスがスコープを外れたときに走るコードをカスタマイズすることができる。

@iterable-company
Copy link
Owner Author

iterable-company commented Dec 15, 2022

Box

Boxを使う場面

コンパイル時にはサイズを知ることができない型があり、正確なサイズを要求する文脈でその型の値を使用する時

後述のListのような構造を自前実装する際、Listがどれくらい続くのかわからないのでサイズがわからないときなど

多くのデータがあり、その所有権を移したいが、その際にデータがコピーされないようにしたい時

大データの構造体の所有権を移したいが、オーバーヘッドを考えてコピーされないようにしたい時
-> スタックに積まれているデータは基本コピーされる。Copy トレイト実装であれ、Clone実装でclone()するときであれ

値を所有する必要があり、特定の型であることではなく、特定のトレイトを実装する型であることのみ気にかけている時

特定のトレイトを実装する型であることを望んでいる場合、実装している型によってサイズが異なる(異なる型のstruct とか)ため、サイズを決められない。

コンパイラが型のサイズを決定する

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

では、Message を確保する際、要素のうち最大のサイズ(i32を3つ分)必要なChangeColorを基準としてMessage型のインスタンスのメモリを確保する。

@iterable-company
Copy link
Owner Author

Deref

deref 参照

以下の3つの場合に、型やトレイトを見つけた時に参照外し型強制を行う。

  • T: Deref<Target=U>の時、&Tから&U
  • T: DerefMut<Target=U>の時、&mut Tから&mut U
  • T: Deref<Target=U>の時、&mut Tから&U

3番目のケースでは可変参照を不変参照へ変換している。
これは借用規則を絶対に破壊しない。
-> 可変参照は1つだけ、不変参照は任意の数OK、可変参照と不変参照を混在できない
逆は、借用規則を壊す恐れがあるため行われない。

@iterable-company
Copy link
Owner Author

RC

参照カウンタ。シングルスレッドで使用されることを想定している。
a.clone() のような呼び出しも可能だが、参照カウンタがインクリメントされていることを明示するために、Rc::clone(&a)と書くことが慣習化している。

@iterable-company
Copy link
Owner Author

iterable-company commented Dec 20, 2022

RefCell

  • 単独の所有権(参照カウンタのように複数のインスタンスが所有権を持つことはできない)
  • 以下の借用原則をコンパイル時ではなく、実行時に保証されればいい。破られれば実行時パニックになる
     - 1つの可変参照か複数の不変参照のどちらかが可能
     - 参照は常に有効でなければならない

通常はコンパイル時に借用原則が検査されるが、

  • 原則が破られることが起きない
  • 実行効率が良い(実行時に借用原則が破られていないかチェックする処理が不要)

シングルスレッドで使われる

  • Box<T> 不変借用も可変借用もコンパイル時に精査できる。 RefCell<T>不変借用も可変借用も実行時に精査する。
  • RefCell<T> が不変でも、RefCell<T> 内の値を可変化できる。

borrow(), borrow_mut() が返す型

borrow() は Ref を返す。
borrow_mut() は RefMut を返す。
RefCell は生きている Ref と RefMut の数を追いかけて、複数の不変借用 or 1つの可変借用 の原則が守られているかをチェックし、破られた時は panic する。

Rc と RefCell を組み合わせて、可変なデータに複数の所有者を持たせる

Rcは複数の所有者を持たせられるが、不変アクセスしかできない。
Rc<RefCell<T>> のような構造にすることで、可変で複数の所有者を持つ構造が作れる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant