Skip to content

Latest commit

 

History

History
79 lines (70 loc) · 1.77 KB

15.traits-vs-generics.md

File metadata and controls

79 lines (70 loc) · 1.77 KB
Using Rust Traits objects vs Generics

Reference: Talk

In case of Generics: (Static Dispatch)

  • Compiler create a new copy of the function for each type it is used with.
  • Better Optimizations:
    • Functions can be optimized differently for each type.
    • Function calls can be limited
  • More code to generate:
    • Larger executables
    • Longer compile times

In case of Trait Objects: (Dynamic Dispatch)

  • Compiler creates one copy of the function, uses trait object's vtable
  • Adds some overhead, prevents type-specific optimzations
  • Less code to generate:
    • smaller executables, faster compile times.
Dynamic Dispatch vs Static Dispatch
  • Static Dispatch: In static dispatch we substitute for functions while compile type.
trait Printable {
  fn format(&self) -> String;
}
impl Printable for i32 {
  fn format(&self) -> String {
    format!("i32 {}", *self)
  }
}
impl Printable for String {
  fn format(&self) -> String {
    format!("String {}", *self)
  }
}
fn print_it<T: Printable>(z: T) {
  println!("{}", z.format());
}
fn main() {
  let a = 123;
  let b = "Hello ".to_string();
  print_it(a);
  print_it(b);
}
  • Dynamic Dispatch
struct Circle { radius: f64 }
struct Square { side: f64 }
trait Shape {
  fn area(&self) -> f64;
}
impl Shape for Square {
  fn area(&self) -> f64 {
    self.side * self.side
  }
}
impl Shape for Circle {
  fn area(&self) -> f64 {
    self.radius * self.radius * std::f64::consts: PI
  }
}
fn main() {
  let shapes: [&Shape; 4] = [
    &Circle { radius: 1.0 },
    &Square { side: 3.0 },
    &Circle { radius: 2.0 },
    &Square { side: 3.0 }
  ];
  for (i, shape) in shapes.iter().enumerate() {
    println!("Shape #{} has area {}", i, shape.area());
  }
}