Rust の視点から見た継承

// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

// データ
pub struct Data {
    id: usize,
    name: String,
}

// 具体的な振る舞い
impl Data {
    fn new(id: usize, name: impl Into<String>) -> Self {
        Self { id, name: name.into() }
    }
}

// 抽象的な振る舞い
trait Named {
    fn name(&self) -> &str;
}

// 実装された振る舞い
impl Named for Data {
    fn name(&self) -> &str {
        &self.name
    }
}
  • Rust の視点、つまり継承というものがこれまで存在しなかった視点からすると、 継承を導入することは、型とトレイトの境界を曖昧にするように見えます。

  • 型は、具体的なデータと、それに関連付けられた振る舞いです。

    トレイトは、型によって実装されなければならない抽象的な振る舞いです。

    クラスは、データ、振る舞い、そしてその振る舞いに対するオーバーライドを組み合わせたものです。

  • Rust から来た立場では、継承可能なクラスは、型でもありトレイトでもある もののように見えます。

  • これは利点ではありません。なぜなら、具体的な型について推論できなくなるからです。

  • この 2 つを分離できないと、ジェネリックな振る舞いと具体的な詳細について 考えるのが難しくなります。なぜなら、OOP ではこれら 2 つの概念が 互いに結び付けられているからです。

  • フラットなフィールドアクセスや型定義における DRY の利便性は、 振る舞いとデータを区別して書くコードが持つ明確さを失う代償に 見合うものではありません。