Rust traits: Difference between revisions
From wikinotes
(→Basics) |
No edit summary |
||
Line 34: | Line 34: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
</blockquote><!-- Basics --> | </blockquote><!-- Basics --> | ||
= Trait Bound Syntax (Generic) = | |||
<blockquote> | |||
You can express the same trait implementation as a generic (allowing you to bind the trait to multiple variables). | |||
<syntaxhighlight lang="rust"> | |||
struct Cat { name: String } | |||
struct Dog { name: String, breed: String } | |||
trait Pet { | |||
fn play(&self); | |||
} | |||
fn play<P: Pet>(&p) { | |||
println!(p.play()); | |||
} | |||
</syntaxhighlight> | |||
</blockquote><!-- As Generic --> | |||
= Object must implement multiple traits = | |||
<blockquote> | |||
Using trait-bound syntax | |||
<syntaxhighlight lang="rust"> | |||
// `p` must implement both Pet and Display | |||
fn play(p: &(impl Pet + Display)) { | |||
println!(p.play()); | |||
} | |||
</syntaxhighlight> | |||
Using <code>where</code> syntax | |||
<syntaxhighlight lang="rust"> | |||
fn play<P>(p: &P) | |||
where | |||
P: Pet + Display | |||
{ | |||
// ... | |||
} | |||
</syntaxhighlight> | |||
</blockquote><!-- Object must implement multiple traits --> | |||
= Default Method Implementation = | |||
<blockquote> | |||
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) | |||
}} | |||
<syntaxhighlight lang="rust"> | |||
struct Cat { name: String } | |||
struct Dog { name: String, breed: String } | |||
trait Pet { | |||
fn play(&self) { | |||
println!("rub") | |||
} | |||
} | |||
</syntaxhighlight> | |||
</blockquote><!-- Default Method --> |
Revision as of 20:09, 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); } impl Pet for Cat { fn play(&self) { println!("you give a ball of yarn to {}", self.name) } }Use trait implementors in method signature
// use trait as param type fn play_with_pet(pet: &impl Pet) { 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);
Trait Bound Syntax (Generic)
You can express the same trait implementation as a generic (allowing you to bind the trait to multiple variables).
struct Cat { name: String } struct Dog { name: String, breed: String } trait Pet { fn play(&self); } fn play<P: Pet>(&p) { println!(p.play()); }
Object must implement multiple traits
Using trait-bound syntax
// `p` must implement both Pet and Display fn play(p: &(impl Pet + Display)) { println!(p.play()); }Using
where
syntaxfn play<P>(p: &P) where P: Pet + Display { // ... }
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") } }