2025/08/06

Rustの関連型について

関連型とは?

Rustの関連型は、トレイトに特定の型を紐づけるための仕組みで、簡単に言うと「このトレイトを実装する型は、必ずこの名前で特定の型を持つ必要がある」というルールを定義するものです。

これと似た機能に「ジェネリクス」がありますが、関連型とジェネリクスは使い分けが重要で、ジェネリクスは、関数や構造体の定義時に型を抽象化するのに対し、関連型はトレイトの実装時に特定の型を決定します。

具体例で理解する関連型

関連型の使い方を理解するために、イテレータを考えてみましょう。Rustのイテレータは、Iteratorというトレイトを実装しています。このトレイトは、Itemという関連型を持っています。


trait Iterator {
  type Item;  // 関連型

  fn next(&mut self) -> Option<Self::Item>
}

このItemがまさに関連型です。Iteratorトレイトを実装する際、Itemには「イテレータが返す要素の型」を指定します。例えば、整数のベクターVec<i32>に対するイテレータは、Itemi32として実装します。


impl Iterator for std::vec::IntoIter<i32> {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    // ... 実装 ...
  }
}

なぜ関連型を使うのか?

関連型を使うメリットは、コードの可読性と柔軟性を高めることにあります。ジェネリクスで同じことをしようとすると


trait Iterator<T> {
  fn next(&mut self) -> Option<T>
}

impl Iterator<i32> for std::vec::IntoIter<i32> {
  ...
}

impl Iterator<i32>といったように、トレイト名に毎回型を明記する必要があり、特に複数のジェネリクス型を持つトレイトではコードが読みにくくなってしまします。

しかし、関連型を使えば、トレイトの実装時に一度だけtype Item = i32;と書くだけで済み、よりシンプルで読みやすいコードとなります。これは、トレイトを実装する側で型を決定するため、トレイトの実装者にとって非常にわかりやすい設計となります。

まとめ

関連型は、トレイトと特定の型を密接に結びつけるための、Rustの強力な機能です。ジェネリクスが「抽象的な型を扱う」のに対し、関連型は「トレイトを実装する際に具体的な型を決定する」という役割を担います。

イテレータのItem型のように、関連型はRustの標準ライブラリでも広く使われています。最初は難しく、ややこしく感じるかもしれませんが、実際にコードを書いてみることで、その便利さを実感できるはずです。