TL;DR

Rust で、ある型が持つ機能を定義し、他の型と共有するための仕組み。メソッドのシグネチャの集まりで、他の言語のインタフェースに近い。

なぜ必要か

The Rust Programming Language によると、トレイトを使うと共通の振る舞いを抽象的に定義できる。トレイト境界と組み合わせると、ジェネリクスの型を「ある振る舞いを持つ任意の型」に制限できる。Effective Rust は、Go や Java のインタフェース、C++ の抽象クラスに当たるものとして紹介し、将来の柔軟性が心配なら具象型ではなくトレイトを受け取るよう勧めている。

仕組み

トレイトを実装する型は、トレイトが定めたメソッドを同じシグネチャで定義しなければならず、コンパイラがそれを確かめる。トレイトはメソッドのデフォルト実装を持てる。デフォルト実装は、同じトレイトの他のメソッドを呼んでもよい。

トレイトを実装できるのは、トレイトか型の少なくとも一方が自分のクレートで定義されている場合だけである。この制約を孤児ルールと呼ぶ。トレイト境界を満たすすべての型にトレイトを実装することもでき、これをブランケット実装と呼ぶ。

例

pub trait Summary {
    fn summarize_author(&self) -> String;
 
    fn summarize(&self) -> String {
        format!("(Read more from {}...)", self.summarize_author())
    }
}

Summary を実装する型は、summarize_author だけを定義すれば summarize も使える。

注意点

インタフェースに似ているが、違いもある。たとえば、外部のクレートのトレイトを外部のクレートの型に実装することはできない。

関連

出典