Traits

Traits #

  • Create functions that we want classes to duplicate (or redefine), but outside a super class
  • Code gets injected into any existing structure (both custom types and standard ones)
  • Trait methods do not need to be fully defined, can define stub methods/declarations
  • Data is not inherited

Advantages:

  • Code reuse: Can create trait with parametrized functions implemented differently for different traits
  • Code hiding: All parts of a trait are exposed, but we can specify exactly which functions should be injected, so no accidental spillover

Example:

struct TeddyBear { name : String, };
struct RedTeddyBear { name : String, };

trait Roar {
    fn roar(&self) {
        println!("{} ROAR!!!", self.name);
    }
}

impl TeddyBear {
    fn sing(&self) {
        println!("SONG!");
    }
}

impl RedTeddyBear {
    fn sing(&self) {
        println!("RED SONG!");
    }
}

impl Roar for TeddyBear {}
impl Roar for RedTeddyBear {
    fn roar(&self) {
        println!("RED ROAR!");
    }
}

Standard Rust traits #

  • Copy: New copy of an instance created instead of moving ownership when using =
  • Clone: Returns a new copy of an instance when calling .clone()
  • Drop: Will define destructor to be used for objects reaching end of scope
  • Display: How to format a type, used by println!() and format!()
  • Debug: Similar to Display but not user-facing
  • Eq: Defines equivalence-relation equality determination for objects of the same time
  • PartialEq: Defines partial equivalence-relation equality determination

Example:

#[derive(Clone/*,...,*/)] // this can try to get the Rust compiler to automatically define an implementation for Clone
struct Point {
    x: u32,
    y: u32,
}

impl Clone for Point {
    fn clone(&self) -> Point {
        Point {x: self.x, y: self.y}
    }
}