関連型
「関連型」を使用すると、内部の型を_出力_型としてトレイト内へローカルに移動することで、コード全体の可読性が向上します。trait 定義の構文は次のとおりです。
#![allow(unused)] fn main() { // `A` と `B` は、`type` キーワードによってトレイト内で定義されます。 // (注: この文脈での `type` は、エイリアスに使われる場合の `type` とは // 異なります)。 trait Contains { type A; type B; // これらの新しい型をジェネリックに参照するための更新された構文。 fn contains(&self, _: &Self::A, _: &Self::B) -> bool; } }
trait Contains を使用する関数では、もはや A や B をまったく表現する必要がないことに注意してください。
// 関連型を使用しない場合
fn difference<A, B, C>(container: &C) -> i32 where
C: Contains<A, B> { ... }
// 関連型を使用する場合
fn difference<C: Contains>(container: &C) -> i32 { ... }
前のセクションの例を、関連型を使用して書き直してみましょう。
struct Container(i32, i32); // 2 つの項目がコンテナ内に格納されているかをチェックするトレイト。 // また、最初または最後の値も取得します。 trait Contains { // メソッドが利用できるジェネリック型をここで定義します。 type A; type B; fn contains(&self, _: &Self::A, _: &Self::B) -> bool; fn first(&self) -> i32; fn last(&self) -> i32; } impl Contains for Container { // `A` と `B` がどの型であるかを指定します。`input` 型が // `Container(i32, i32)` である場合、`output` 型は // `i32` と `i32` に決定されます。 type A = i32; type B = i32; // `&Self::A` と `&Self::B` もここでは有効です。 fn contains(&self, number_1: &i32, number_2: &i32) -> bool { (&self.0 == number_1) && (&self.1 == number_2) } // 最初の数値を取得します。 fn first(&self) -> i32 { self.0 } // 最後の数値を取得します。 fn last(&self) -> i32 { self.1 } } fn difference<C: Contains>(container: &C) -> i32 { container.last() - container.first() } fn main() { let number_1 = 3; let number_2 = 10; let container = Container(number_1, number_2); println!("コンテナは {} と {} を含んでいますか: {}", &number_1, &number_2, container.contains(&number_1, &number_2)); println!("最初の数値: {}", container.first()); println!("最後の数値: {}", container.last()); println!("差は: {}", difference(&container)); }