実践Rust入門 10日目

8章3〜5節まで。

Rustでの静的/動的ディスパッチの仕組みと存在impl Trait、トレイトの関連xxについて。
5節以外は読むだけスタイルで進めた。

Rustの機能と静的/動的ディスパッチの話は割と面白かった。
しかし、ジェネリクスとトレイトの使い方に慣れないとなぁ。

おぼえがき
  • 静的ディスパッチは、ジェネリクスで実現
    • 静的ディスパッチは、通常の関数呼び出し形式に変換する
    • メリット
      • 実行時のオーバーヘッドがなくなる(通常の関数と同じ)
      • インライン化による最適化なども効くようになる
    • デメリット
      • 型ごとに関数本体をコピーするため、コードサイズが大きくなる
      • 複数の型を混在させられない。以下はコンパイルエラー
        • let mut v: Vec<Display> = vec![];
        • v.push(true); v.push(1i32);
  • 動的ディスパッチは、トレイトオブジェクトで実現
    • 動的ディスパッチは、コンパイル時に内部データを持たせて、実行時型に型を判別する
    • メリット − コードはコンパクトなる
      • 柔軟性。以下はコンパイルエラーにならない
        • let mut v: Vec<&dyn Display> = vec![];
        • v.push(&true); v.push(&1i32);
    • デメリット
      • 実行時のコストが上がる
    • トレイトオブジェクトを作るには、オブジェクト安全性を満たす必要がある
      • オブジェクト安全性については、参考URLのみで本書では説明なし
  • impl Trait
    • 全称impl Trait: fn func(arg: impl TraitName)
    • 存在impl Trait: fn func() -> impl TraitName
      • あるトレイトを実装した型を明示できるが、戻り値を返された側は、その型以外の操作ができない
        • ちょっと違うけど、サブクラスのメソッドをスーパークラスが使えないようなものに似ている
        • 明示された型の操作しか受け付けない
      • 匿名型のクロージャを返す関数の戻り値の型に使える
        • トレイトオブジェクトも使えるが、動的ディスパッチになる
          • トレイトオブジェクトを作るコストもある
        • 存在impl Traiであれば、静的ディスパッチになる
        • Rust1.26まではトレイトオブジェクトを作る方法しかなかったっぽい
  • トレイトの関連関数
    • 引数にselfをとらない関数は、トレイトの関連関数になる
    • Javaでいうクラス関数とかstatic関数とか呼んでるものっぽい
    • TraitName::func()で呼び出す
  • トレイトの関連定数
    • トレイト内にconstを付けて定数も作れる
    • trait TraitName { const CONST_VALUE: u32; }
    • TraitName::CONST_VALUEで参照
  • トレイトの関連型
    • トレイトに関連付いた型を定義できる。
      • trait TraitName { type TypeName; }
      • trait TraitName { type TypeName: TraitBounds; }
    • trait内、ブロック内では、Self::TypeNameでアクセスできる
      • fn func(&self, arg: Self::TypeName)
    • 型の実体は、実装側で定義
      • impl type TypeName = String;
      • 関連関数・関連定数はデータ型にもある機能だが、関連型はトレイトにしかない
課題
  • オブジェクト安全性ってなんだろう
  • 関連型とジェネリクスの使い分け
    • P332のコラムも読み返す
気になったこと

− P330の本文中の「[:トレイト制約]」って、「トレイト境界」のことなのかな
- そういえばトレイト境界って変な名前

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

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