実践Rust入門 8日目 その1

7章9節。

独自のベクタを実装しながら、ライフタイムについて学ぶ構成。

所有権の移動とライフタイムの絡みは面倒だなぁ。
コンパイラくんが色々検出するためなんだろうけど、ライフタイム指定子を使いこなせる気がしない。

とにかく書いてコンパイルエラー量産して慣れるしかないか。

おぼえがき
  • ライフタイム指定子

    • &'a self'a
    • 関数・メソッドの戻り値が参照型の場合、戻り値のライフタイムは以下で推論される
      • 引数の中で参照型が1つだけなら、その引数から借用する
      • 第1引数が&selfまたは&mut selfのメソッドなら、selfから借用する
      • それ以外の場合はライフタイムを省略できない(コンパイルエラー)
    • whare節でライフタイムの長短を明示できる
      • where 'b: 'a bはaよりライフタイムが長いと明示
  • 'staticライフタイム

    • プログラム終了まで続く特別なライフタイム
    • static変数の値、リテラルなどコンパイル時に値が確定するものにしか使えない(生ポ経由なら可だけどunsafe)
      • 要は静的領域のデータに対する参照にしか'staticは使えないということっぽい
  • 借用経由(&mut self)では、所有権は移動できない

    • けど交換はできるという変な理屈
      • 交換にはlet dest_area = std::mem::replace(&mut src_area, dumy_val);を使う
      • Option<T>型には交換のための便利なメソッドが用意されている
        • pub fn take(&mut self) -> Option<T>;
          • 所有権を移動し、元の場所にはNoneを返す
        • pub fn replace(&mut self, value: T) -> Option<T>;
          • 所有権を移動し、元の場所にはSome(value)を返す
  • 構造体や列挙型のライフタイム

    • 参照型のフィールドをもたせる場合は、定義にライフタイム指定子をつけること
  • 列挙型とnullableポインタ最適化

    • Option<T>などの列挙型は、バリアントを識別するためのフィールド「タグ」を持つ
    • タグのサイズは4byte。例えばOption<T>は値4byte+タグ4byte=計8byteが型のサイズ
    • しかし、下記条件を満たす場合、nullableポインタ最適化の条件を満たせばタグは省略される。
      1. 2つのバリアントを持つ
      2. 一方のバリアントはフィールドを持たない
      3. もう一方のバリアントはフィールドを持つが、そのデータ型にとって全ビット0の状態は不正である
    • Option<T>型は、上記条件を満たすため、タグは省略される
    • 要は、列挙型の値がゼロならフィールドを持ったバリアントだと判断可能ということか
      • 必要なスペースは減るけど、実行コストは上がらないの?
      • ん、結局バリアントの識別は誰がいつ必要とする話なんだっけ
課題
  • P277 ジェネリクスに対するライフタイムの説明はピンときてないので整理が必要
  • P280 nullableポインタ最適化の話はそもそもの識別が何のためにあるのか要確認
  • トレイトの構文はよく分からん。多分、8章で詳しくやるっぽい
気になったこと
  • P280のコラムからの参照されている「図5.6」が見当たらない

実践Rust入門[言語仕様から開発手法まで]

実践Rust入門[言語仕様から開発手法まで]