これは、Rustプログラミング言語の第2版で触れられています。ただし、もう少し詳しく見てみましょう。
簡単な例から始めましょう。
特性メソッドを使用するのが適切なのはいつですか?
遅延バインディングを提供する方法は複数あります。
trait MyTrait {
fn hello_word(&self) -> String;
}
または:
struct MyTrait<T> {
t: T,
hello_world: fn(&T) -> String,
}
impl<T> MyTrait<T> {
fn new(t: T, hello_world: fn(&T) -> String) -> MyTrait<T>;
fn hello_world(&self) -> String {
(self.hello_world)(self.t)
}
}
実装/パフォーマンス戦略を無視して、上記の両方の抜粋により、ユーザーは動的な方法hello_worldで動作方法を指定できます。
1つの違い(意味的に)は、trait実装が、特定の型をT実装するtrait場合、hello_world常に同じ動作をすることを保証するのに対し、struct実装ではインスタンスごとに異なる動作を許可することです。
メソッドの使用が適切かどうかは、ユースケースに依存します!
関連付けられたタイプを使用するのが適切なのはいつですか?
trait上記のメソッドと同様に、関連する型はレイトバインディングの形式です(コンパイル時に発生します)。これにより、のユーザーは、trait特定のインスタンスに対してどの型に置き換えるかを指定できます。それが唯一の方法ではありません(したがって問題です):
trait MyTrait {
type Return;
fn hello_world(&self) -> Self::Return;
}
または:
trait MyTrait<Return> {
fn hello_world(&Self) -> Return;
}
上記のメソッドの遅延バインディングと同等です。
- 最初のものは、与えられたもの
SelfにReturn関連付けられた単一の
- 二つ目は、代わりに、実現可能
MyTraitのためのSelf複数のためにReturn
どの形式がより適切であるかは、単一性を強制することが理にかなっているかどうかによって異なります。例えば:
Deref unicityがないとコンパイラーは推論中に狂ってしまうため、関連する型を使用します
Add 2つの引数が与えられると論理的な戻り値の型が存在すると考えられているため、関連付けられた型を使用します
ご覧のとおりDeref、明らかなユースケース(技術的な制約)ですが、のケースAddはあまり明確ではありません。i32 + i32どちらか一方i32またはComplex<i32>コンテキストに応じて譲歩することには意味があるのでしょうか?それでも、著者は判断を下して、追加の戻り値の型のオーバーロードは不要であると判断しました。
私の考えでは、正解はありません。それでも、unicityの引数を超えて、関連する型は指定する必要のあるパラメーターの数を減らすため、トレイトの使用を容易にすることを述べます。したがって、通常のトレイトパラメーターを使用する柔軟性の利点が明らかでない場合は、関連するタイプから始めることをお勧めします。
trait/struct MyTrait/MyStruct1つimpl MyTrait forまたはを許可しますimpl MyStruct。 汎用であるためtrait MyTrait<Return>、複数implのを使用できます。Returnどのタイプでもかまいません。一般的な構造体は同じです。