ジェネリック境界

ジェネリックプログラミングをしていると、型パラメータが特定の機能を持っていることを規定するため、トレイトに境界(bound)を設ける必要があることがよくあります。例えば、以下の例では、引数のDisplayトレイトを用いてプリントを行うため、TDisplayを持っていることを規定しています。つまり、「TDisplayを実装 していなくてはならない 」という意味です。

// Define a function `printer` that takes a generic type `T` which // must implement trait `Display`. // `Display`トレイトを実装している`T`を引数として取る // `printer`という関数を定義。 fn printer<T: Display>(t: T) { println!("{}", t); }

境界は、ジェネリクスを全ての型ではなく、一定条件を満たす型に対してのみ適用するためにあります。つまり

訳注: <T: Display><T>の部分集合であることを意識すると、「境界」という言葉の意味がしっくり来ると思います。

struct S<T: Display>(T); // Error! `Vec<T>` does not implement `Display`. This // specialization will fail. // エラー! `Vec<T>`は`Display`を実装していないため、この特殊化 // は失敗します。 let s = S(vec![1]);

境界のもう一つの効果は、ジェネリック型のインスタンスが、境界条件となるトレイトのメソッドにアクセスすることができるようになる点です。以下がその例です。

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

付け加えておくと、where句を用いて境界を適用することもできます。場合によってはこちらの記法を使用したほうが読みやすくなる場合もあります。

参照

std::fmt, 構造体(struct), トレイト