typestar

Trait objects in Rust

A Vec of Box<dyn Trait> holds different concrete types behind one interface.

trait Check {
    fn name(&self) -> &str;
    fn passes(&self, text: &str) -> bool;
}

struct MinLength(usize);
struct NoSpaces;

impl Check for MinLength {
    fn name(&self) -> &str {
        "min length"
    }
    fn passes(&self, text: &str) -> bool {
        text.len() >= self.0
    }
}

impl Check for NoSpaces {
    fn name(&self) -> &str {
        "no spaces"
    }
    fn passes(&self, text: &str) -> bool {
        !text.contains(' ')
    }
}

fn main() {
    let checks: Vec<Box<dyn Check>> =
        vec![Box::new(MinLength(3)), Box::new(NoSpaces)];

    for candidate in ["ada", "ada lovelace", "x"] {
        let failed: Vec<&str> = checks
            .iter()
            .filter(|c| !c.passes(candidate))
            .map(|c| c.name())
            .collect();
        println!("{candidate:?} failed {:?}", failed);
    }
}

How it works

  1. dyn Trait dispatches at run time through a vtable.
  2. Boxing is what makes the sizes uniform.
  3. Generics would force every element to be the same type.

Keywords and builtins used here

The run, in numbers

Lines
39
Characters to type
682
Tokens
234
Three-star pace
110 tpm

At the three-star pace of 110 tokens a minute, this run takes about 128 seconds.

Type this snippet

Step 1 of 3 in Dynamic dispatch, step 16 of 19 in Traits & generics.

← Previous Next →