Rustのトレイト(Trait)入門|インターフェースの実装

先生

Rustのトレイトはインターフェースの進化形!共通の振る舞いを定義して、コードをより柔軟に、再利用しやすくしませんか?

Rustのトレイトとは?インターフェースの基本

Rustにおけるトレイトは、他の言語でいうところのインターフェースや抽象クラスに相当する機能です。トレイトを使用することで、複数の型に対して共通の振る舞いを定義できます。これにより、柔軟で再利用性の高いコードを書くことが可能になります。

トレイトはtraitキーワードを使って定義します。トレイト内では、メソッドのシグネチャ(名前、引数、戻り値の型)を定義します。メソッドの実装は、そのトレイトを実装する型が行います。

例えば、以下のようにDisplayというトレイトを定義できます。

trait Display {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
}

このトレイトは、fmtというメソッドを持つことを定義しています。fmtメソッドは、自身(self)への参照と、フォーマッタオブジェクトへの可変参照を受け取り、std::fmt::Result型を返します。

トレイトの実装:型に共通の振る舞いを付与する

トレイトを型に実装するには、implキーワードを使用します。implブロック内で、トレイトで定義されたメソッドを実際に実装します。

例えば、Point構造体にDisplayトレイトを実装する例を見てみましょう。

struct Point { 
    x: i32,
    y: i32,
}
impl Display for Point {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

このコードでは、Point構造体に対してDisplayトレイトを実装しています。fmtメソッドの中で、Pointxyの値をフォーマットして文字列として出力しています。

これにより、Point型のインスタンスをprintln!マクロなどで直接出力できるようになります。

fn main() {
    let p = Point { x: 10, y: 20 };
    println!("{}", p); // Output: (10, 20)
}

デフォルト実装:共通処理をトレイトに定義する

トレイトでは、メソッドにデフォルト実装を提供できます。これにより、トレイトを実装する型は、必要に応じてメソッドをオーバーライドできます。

例えば、Summaryというトレイトを定義し、summarizeメソッドにデフォルト実装を与えることができます。

trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

この例では、summarizeメソッドはデフォルトで”(Read more…)”という文字列を返します。型がsummarizeメソッドを実装しない場合、このデフォルト実装が使用されます。

型がsummarizeメソッドを独自に実装することも可能です。

struct NewsArticle {
    headline: String,
    location: String,
    author: String,
    content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

トレイト境界:ジェネリクス型を制約する

トレイト境界を使用すると、ジェネリクス型が特定のトレイトを実装していることを要求できます。これにより、ジェネリクス関数や構造体が、特定の振る舞いを持つ型に対してのみ動作するように制限できます。

例えば、display_summaryという関数を定義し、引数がSummaryトレイトを実装していることを要求できます。

fn display_summary<T: Summary>(item: &T) {
    println!("Summary: {}", item.summarize());
}

この関数は、Summaryトレイトを実装している任意の型のインスタンスを受け取り、summarizeメソッドの結果を出力します。

T: Summaryは、トレイト境界と呼ばれるもので、TSummaryトレイトを実装する型でなければならないことを意味します。

参考リンク

まとめ

この記事では、Rustのトレイトの基本的な概念と使い方について解説しました。トレイトを使用することで、異なる型に対して共通の振る舞いを定義し、柔軟で再利用性の高いコードを作成できます。トレイト境界を使用すると、ジェネリクス型を制約し、より安全なコードを書くことができます。Rustのトレイトを理解し、効果的に活用することで、より高品質なソフトウェア開発を目指しましょう。