Dev Study
← 解説「dyn Trait — 異なる型を同じ入れ物に」に戻る

サンプルコードで身につける: dyn Trait — 異なる型を同じ入れ物に

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1最小のトレイトオブジェクト — 2つの型を1つの Vec に

Dog と Cat という別々の型を Box<dyn Speak> で包むと、1つの Vec に収められる最小例です。取り出した要素は「Speak を実装した何か」としてしか見えませんが、speak() は呼び出せます。まずは「dyn Trait = 具体的な型を消して、振る舞いの約束だけ残す」という感覚をつかんでください。

Rust

2実行時に中身が決まる Box<dyn Trait>

1つの変数にどの型が入るかが、実行時の値によって初めて決まる例です。コンパイル時に型を1つへ固定できない場面こそトレイトオブジェクトの出番で、変数の型は Box<dyn Message> のまま変わりません。時刻や設定によって振る舞いを切り替える処理の骨格です。

Rust

3Box<dyn Trait> を返す工場関数

戻り値を Box<dyn Compressor> にすると、1つの関数が分岐によって異なる型を返せます。ジェネリクスの戻り値はコンパイル時に1つの型へ固定されるため、この形は dyn でしか書けません。実務では設定文字列から実装を組み立てる「ファクトリ関数」として頻出します。

Rust

4構造体のフィールドで部品を差し替える

Box<dyn Formatter> をフィールドに持たせると、構造体の一部の振る舞いを実行時に丸ごと差し替えられます。Logger 本体のコードには手を入れずに、整形方法だけを交換できるのがポイントです。依存する部品をトレイトで抽象化しておく、実務の設計パターンの入り口です。

Rust

5図形リストの集計 — dyn とイテレータ

描画対象の図形リストを Vec<Box<dyn Shape>> で持ち、イテレータで面積を合計する実務寄りの例です。リストに新しい図形の型を追加しても、集計側の map や sum のコードは1行も変わりません。「種類は増えるが操作は同じ」というデータにトレイトオブジェクトが効きます。

Rust