Rust に継承がないのはなぜですか?

// 著作権 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

pub struct Id {
    pub id: u32
}

impl Id {
    // メソッド
}

// 🔨❌、Rust には継承がありません!
pub struct Data: Id {
    // 継承された "id" フィールド
    pub name: String,
}

impl Data {
    // メソッドですが、Id のメソッドも含まれるか、
    // あるいはそれらのメソッドをオーバーライドする可能性もあります。
}

// ✅
pub struct Data {
    pub id: Id,
    pub name: String,
}

impl Data {
    // トレイト由来ではない Data のすべてのメソッド。
}

impl SomeTrait for Data {
    // トレイトの実装は別個の impl ブロックに記述します。
}
  • 継承にはいくつもの欠点があります。

  • デフォルトで異種の型を混在させられる:

    クラス継承では、異なるクラスの型を暗黙的に相互交換可能なものとして扱えますが、 具体的な型や、ある型が別の型と同一であるかどうかを指定できません。

    これにより、等値判定や比較のような操作で、エラーを投げたり別の形で パニックしたりする比較や等値判定が許されてしまいます。

  • データ構造の構成要素とその振る舞いを決める正となる情報源が複数ある:

    型のフィールドは継承階層によって見えにくくなります。

    型のメソッドは親型をオーバーライドしているかもしれず、あるいは子型に よってオーバーライドされるかもしれないため、複数の当事者によって保守 される複雑なコードベースでは、その型の振る舞いを把握するのが困難です。

  • デフォルトの動的ディスパッチでは、vtable のルックアップによる オーバーヘッドが加わる:

    動的ディスパッチを機能させるには、呼び出すべきメソッドや、その型に ついて実行時にのみ分かるその他の情報を格納する場所が必要です。

    この格納先が、その値に対する vtable です。メソッド呼び出しでは、 コンパイル時に型が分かっている場合のメソッド呼び出しよりも多くの 間接参照が必要になります。