Rust traits
Traits are similar to interfaces with some key differences:
- they can have a default implementation.
- they can behave like refinements, only adding the method if the trait has been imported into namespace
Basics
NOTE:
If the trait method implementation is in a different file than your type,
you'll need to import the trait into the current namespace so it is usable on your object!
ex.std::io::BufRead
Define and implement trait
struct Cat { name: String } struct Dog { name: String, breed: String } // all implementors of 'Pet' must have method 'play' with this method signature trait Pet { fn play(&self) -> bool; } impl Pet for Cat { fn play(&self) -> bool { println!("you give a ball of yarn to {}", self.name); true } }Use trait implementors in method signature
// use trait as param type fn play_with_pet(pet: &impl Pet) -> bool { pet.play(); } let cat = Cat{name: "maize".to_string()}; let dog = Dog{name: "midnight".to_string(), breed: "?".to_string()}; play_with_pet(&cat); play_with_pet(&dog);
In Function Signatures
As Param
// with impl fn play_with_pet(pet: &impl Pet) -> bool {} // trait-bound-syntax (generic) fn play_with_pet<P: Pet>(pet: P) -> bool {}Requires object implements multiple interfaces
// with impl fn play_with_pet(pet: &(impl Pet + Display)) -> bool {} // with where clause fn play_with_pet<P>(p: P) -> bool where P: Pet + Display {}As Return
If you're only ever returning one possible concretion, you can do this:
fn gimme_pet() -> impl Pet { // ... }But if you may return different types of implementors of Pet, you'll need to do this: https://doc.rust-lang.org/stable/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
// TODO
Default Method Implementation
Unlike interfaces in most other languages, you can define a default method implementation on the trait.
TODO:
can you require fields as well? (in this case, name)
struct Cat { name: String } struct Dog { name: String, breed: String } trait Pet { fn play(&self) { println!("rub") } }Blanket Implementations
You can write traits that are automatically applied all objects,
that implements another trait.
// every object that implements `Display` // will automagically be assigned this `to_string()` method. impl<T: Display> ToString for T { fn to_string(v: T) -> String { format!("{}", ) } }