Rust traits: Difference between revisions
From wikinotes
No edit summary |
No edit summary |
||
Line 10: | Line 10: | ||
// all implementors of 'Pet' must have method 'play' with this method signature | // all implementors of 'Pet' must have method 'play' with this method signature | ||
trait Pet { | trait Pet { | ||
fn play(&self); | fn play(&self) -> bool; | ||
} | } | ||
impl Pet for Cat { | impl Pet for Cat { | ||
fn play(&self) { | fn play(&self) -> bool { | ||
println!("you give a ball of yarn to {}", self.name) | println!("you give a ball of yarn to {}", self.name); | ||
true | |||
} | } | ||
} | } | ||
Line 24: | Line 25: | ||
<syntaxhighlight lang="rust"> | <syntaxhighlight lang="rust"> | ||
// use trait as param type | // use trait as param type | ||
fn play_with_pet(pet: &impl Pet) { | fn play_with_pet(pet: &impl Pet) -> bool { | ||
pet.play(); | pet.play(); | ||
} | } | ||
Line 35: | Line 36: | ||
</blockquote><!-- Basics --> | </blockquote><!-- Basics --> | ||
= | = In Function Signatures = | ||
<blockquote> | <blockquote> | ||
== As Param == | |||
<blockquote> | |||
<syntaxhighlight lang="rust"> | |||
// with impl | |||
fn play_with_pet(pet: &impl Pet) -> bool {} | |||
// trait-bound-syntax (generic) | |||
fn play_with_pet<P: Pet>(pet: P) -> bool {} | |||
</syntaxhighlight> | |||
Requires object implements multiple interfaces | |||
<syntaxhighlight lang="rust"> | <syntaxhighlight lang="rust"> | ||
// 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 | |||
{} | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
</blockquote><!-- | </blockquote><!-- Params --> | ||
= | == As Return == | ||
<blockquote> | <blockquote> | ||
If you're only ever returning one possible concretion, you can do this: | |||
<syntaxhighlight lang="rust"> | <syntaxhighlight lang="rust"> | ||
fn gimme_pet() -> impl Pet { | |||
fn | // ... | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
But if you may return different types of implementors of Pet, you'll need to do this: | |||
<syntaxhighlight lang="rust"> | <syntaxhighlight lang="rust"> | ||
// TODO | |||
</syntaxhighlight> | </syntaxhighlight> | ||
</blockquote><!-- | </blockquote><!-- As Return --> | ||
</blockquote><!-- Method Signatures --> | |||
= Default Method Implementation = | = Default Method Implementation = |
Revision as of 20:23, 8 February 2023
Traits are similar to interfaces except they can have a default implementation.
Basics
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:
// 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") } }