Trait Objects

We’ve seen how a function can take arguments which implement a trait:

  1. use std::fmt::Display;
  2. fn print<T: Display>(x: T) {
  3. println!("Your value: {x}");
  4. }
  5. fn main() {
  6. print(123);
  7. print("Hello");
  8. }

However, how can we store a collection of mixed types which implement Display?

  1. fn main() {
  2. let xs = vec![123, "Hello"];
  3. }

For this, we need trait objects:

  1. use std::fmt::Display;
  2. fn main() {
  3. let xs: Vec<Box<dyn Display>> = vec![Box::new(123), Box::new("Hello")];
  4. for x in xs {
  5. println!("x: {x}");
  6. }
  7. }

Memory layout after allocating xs:

24.7. Trait Objects - 图1

Similarly, you need a trait object if you want to return different types implementing a trait:

  1. fn numbers(n: i32) -> Box<dyn Iterator<Item=i32>> {
  2. if n > 0 {
  3. Box::new(0..n)
  4. } else {
  5. Box::new((n..0).rev())
  6. }
  7. }
  8. fn main() {
  9. println!("{:?}", numbers(-5).collect::<Vec<_>>());
  10. println!("{:?}", numbers(5).collect::<Vec<_>>());
  11. }