The Problem
A trait that is generic over its container type has type specification
requirements - users of the trait must specify all of its generic types.
In the example below, the Contains trait allows the use of the generic
types A and B. The trait is then implemented for the Container type,
specifying i32 for A and B so that it can be used with fn difference().
Because Contains is generic, we are forced to explicitly state all of the
generic types for fn difference(). In practice, we want a way to express that
A and B are determined by the input C. As you will see in the next
section, associated types provide exactly that capability.
1. struct Container(i32, i32);
3. // A trait which checks if 2 items are stored inside of container.
4. // Also retrieves first or last value.
5. trait Contains<A, B> {
6. fn contains(&self, &A, &B) -> bool; // Explicitly requires `A` and `B`.
7. fn first(&self) -> i32; // Doesn't explicitly require `A` or `B`.
8. fn last(&self) -> i32; // Doesn't explicitly require `A` or `B`.
9. }
11. impl Contains<i32, i32> for Container {
12. // True if the numbers stored are equal.
13. fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
14. (&self.0 == number_1) && (&self.1 == number_2)
15. }
17. // Grab the first number.
18. fn first(&self) -> i32 { self.0 }
20. // Grab the last number.
21. fn last(&self) -> i32 { self.1 }
22. }
24. // `C` contains `A` and `B`. In light of that, having to express `A` and
25. // `B` again is a nuisance.
26. fn difference<A, B, C>(container: &C) -> i32 where
27. C: Contains<A, B> {
28. container.last() - container.first()
29. }
31. fn main() {
32. let number_1 = 3;
33. let number_2 = 10;
35. let container = Container(number_1, number_2);
37. println!("Does container contain {} and {}: {}",
38. &number_1, &number_2,
39. container.contains(&number_1, &number_2));
40. println!("First number: {}", container.first());
41. println!("Last number: {}", container.last());
43. println!("The difference is: {}", difference(&container));
44. }
