他のトレイトを拡張する

型と同様に、外部トレイトを拡張したい場合もあります。特に、 あるトレイトを実装する すべて の型に新しいメソッドを追加したい場合です。

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

mod ext {
    use std::fmt::Display;

    pub trait DisplayExt {
        fn quoted(&self) -> String;
    }

    impl<T: Display> DisplayExt for T {
        fn quoted(&self) -> String {
            format!("'{}'", self)
        }
    }
}

pub use ext::DisplayExt as _;

assert_eq!("dad".quoted(), "'dad'");
assert_eq!(4.quoted(), "'4'");
assert_eq!(true.quoted(), "'true'");
  • 一度に 複数 の型へ新しい振る舞いを追加した点を強調してください。.quoted() は文字列スライス、数値、真偽値に対して呼び出せます。これらはすべて Display トレイトを実装しているからです。

    この種の拡張トレイトパターンでは、 ブランケット実装 を使います。

    ブランケット実装は、impl ブロックで指定されたトレイト境界を満たすすべての 型 T に対してそのトレイトを実装するものです。この場合、唯一の要件は TDisplay トレイトを実装していることです。

  • 学生の注意を DisplayExt::quoted の実装に向けてください。T については、 Display を実装していること以外に何も仮定できません。ロジックはすべて、 Display のメソッドか、ほかのトレイトを必要としない関数/マクロの どちらかを使わなければなりません。

    たとえば、T に対して format! は使えますが、.to_uppercase() は 呼び出せません。必ずしも String とは限らないからです。

    T に追加のトレイト境界を導入することもできますが、そうすると この拡張トレイトを利用できる型の集合が制限されます。

  • 慣例として、拡張トレイトの名前は、拡張対象のトレイト名の後ろに Ext 接尾辞を付けたものにします。上の例では DisplayExt です。

  • 標準ライブラリのトレイトに新しい機能を追加するクレートも あります。

    • itertools クレートは、Iterator を拡張する Itertools トレイトを 提供します。これは interleaveunique など、多くの イテレータアダプタを追加します。メソッドチェーンで構築された イテレータパイプラインに対して、新しいアルゴリズム上の構成要素を提供します。

    • futures クレートは、Future トレイトを拡張する FutureExt トレイトを提供し、新しいコンビネータやヘルパーメソッドを追加します。

さらに掘り下げる

  • 拡張トレイトは、安定版メソッドと実験的メソッドをライブラリが区別するためにも 使えます。

    安定版メソッドは、トレイト定義の一部です。

    実験的メソッドは、より制約の少ない安定性ポリシーを持つ別のライブラリで 定義された拡張トレイトを通じて提供されます。その後、一部のユーティリティ メソッドは、有用性が実証され、設計が洗練されると、コアのトレイト定義へと 「昇格」されます。

  • 拡張トレイトは、dyn 互換でないトレイト を 2 つに分割するためにも 使えます:

    • dyn 互換なコア。dyn 互換性の要件を満たすメソッドだけに 制限されます。
    • 拡張トレイト。dyn 互換でない残りのメソッド(たとえば、 ジェネリックなパラメータを持つメソッド)を含みます。
  • コアトレイトを実装する具象型は、拡張トレイトに対するブランケット実装の おかげで、すべてのメソッドを呼び出せます。トレイトオブジェクト (dyn CoreTrait)は、コアトレイト上のすべてのメソッドに加えて、 Self: Sized を必要としない拡張トレイト上のメソッドも呼び出せます。