関連型が必要になる状況
コンテナ型に、その要素に対してジェネリックなトレイトを実装した場合、そのトレイトを使用する者は全てのジェネリック型を明記 しなくてはなりません 。
以下の例ではContains
トレイトはジェネリック型A
とB
の使用を許しています。その後、Container
型に対してContains
を実装していますが、その際後にfn difference()
が使用できるように、A
、B
はそれぞれi32
と明記されています。
Contains
はジェネリックトレイトなので、fn difference()
では 全ての ジェネリック型を宣言しなくてはなりません。実際のところ、A
とB
は 引数 であるC
によって決定されていて欲しいにも関わらず、です。これは次のページで紹介する関連型と呼ばれる機能によって可能です。
struct Container(i32, i32); // A trait which checks if 2 items are stored inside of container. // Also retrieves first or last value. // 2つの要素がコンテナ型の中にあることをチェックするトレイト // また、最初と最後の値を取得することもできる trait Contains<A, B> { fn contains(&self, _: &A, _: &B) -> bool; // Explicitly requires `A` and `B`. // `A`と`B`の両方を明示的に要求する fn first(&self) -> i32; // Doesn't explicitly require `A` or `B`. // `A`、`B`いずれも要求しない fn last(&self) -> i32; // Doesn't explicitly require `A` or `B`. // `A`、`B`いずれも要求しない } impl Contains<i32, i32> for Container { // True if the numbers stored are equal. // コンテナ内の2つの要素が等しければTrueを返す fn contains(&self, number_1: &i32, number_2: &i32) -> bool { (&self.0 == number_1) && (&self.1 == number_2) } // Grab the first number. // ひとつ目の値を取得 fn first(&self) -> i32 { self.0 } // Grab the last number. // 最後(2つめ)の値を取得 fn last(&self) -> i32 { self.1 } } // `C` contains `A` and `B`. In light of that, having to express `A` and // `B` again is a nuisance. // `A`と`B`は`C`に保持されていることを考慮すると、`A`と`B`を // 2度も書くのは面倒 fn difference<A, B, C>(container: &C) -> i32 where C: Contains<A, B> { container.last() - container.first() } fn main() { let number_1 = 3; let number_2 = 10; let container = Container(number_1, number_2); println!("Does container contain {} and {}: {}", &number_1, &number_2, container.contains(&number_1, &number_2)); println!("First number: {}", container.first()); println!("Last number: {}", container.last()); println!("The difference is: {}", difference(&container)); }