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
dyn Traitdispatches at run time through a vtable.- Boxing is what makes the sizes uniform.
- Generics would force every element to be the same type.
Keywords and builtins used here
BoxMinLengthNoSpacesVecbooldynfnforimplinletmainnamepassesselfstrstructtraitusize
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.
Step 1 of 3 in Dynamic dispatch, step 16 of 19 in Traits & generics.