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);
  2. // A trait which checks if 2 items are stored inside of container.
  3. // Also retrieves first or last value.
  4. trait Contains<A, B> {
  5. fn contains(&self, &A, &B) -> bool; // Explicitly requires `A` and `B`.
  6. fn first(&self) -> i32; // Doesn't explicitly require `A` or `B`.
  7. fn last(&self) -> i32; // Doesn't explicitly require `A` or `B`.
  8. }
  9. impl Contains<i32, i32> for Container {
  10. // True if the numbers stored are equal.
  11. fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
  12. (&self.0 == number_1) && (&self.1 == number_2)
  13. }
  14. // Grab the first number.
  15. fn first(&self) -> i32 { self.0 }
  16. // Grab the last number.
  17. fn last(&self) -> i32 { self.1 }
  18. }
  19. // `C` contains `A` and `B`. In light of that, having to express `A` and
  20. // `B` again is a nuisance.
  21. fn difference<A, B, C>(container: &C) -> i32 where
  22. C: Contains<A, B> {
  23. container.last() - container.first()
  24. }
  25. fn main() {
  26. let number_1 = 3;
  27. let number_2 = 10;
  28. let container = Container(number_1, number_2);
  29. println!("Does container contain {} and {}: {}",
  30. &number_1, &number_2,
  31. container.contains(&number_1, &number_2));
  32. println!("First number: {}", container.first());
  33. println!("Last number: {}", container.last());
  34. println!("The difference is: {}", difference(&container));
  35. }

See also:

structs, and traits