Traits: methods + Self
+ access
Four ‘trait’ point of a trait
A trait
is:
- a collection of methods
- defined for an unknown type:
Self
- They can access other methods declared in the same trait.
- Traits can be implemented for any data type.
In the example below, we define Animal, a group of methods. The Animal trait is then implemented for the Sheep data type, allowing the use of methods from Animal with a Sheep.
struct Sheep { naked: bool, name: &'static str } trait Animal { // Associated function signature; `Self` refers to the implementor type. fn new(name: &'static str) -> Self; // Method signatures; these will return a string. fn name(&self) -> &'static str; fn noise(&self) -> &'static str; // Traits can provide default method definitions. fn talk(&self) { println!("{} says {}", self.name(), self.noise()); } } impl Sheep { fn is_naked(&self) -> bool { self.naked } fn shear(&mut self) { if self.is_naked() { // Implementor methods can use the implementor's trait methods. println!("{} is already naked...", self.name()); } else { println!("{} gets a haircut!", self.name); self.naked = true; } } } // Implement the `Animal` trait for `Sheep`. impl Animal for Sheep { // `Self` is the implementor type: `Sheep`. fn new(name: &'static str) -> Sheep { Sheep { name: name, naked: false } } fn name(&self) -> &'static str { self.name } fn noise(&self) -> &'static str { if self.is_naked() { "baaaaah?" } else { "baaaaah!" } } // Default trait methods can be overridden. fn talk(&self) { // For example, we can add some quiet contemplation. println!("{} pauses briefly... {}", self.name, self.noise()); } } fn main() { // Type annotation is necessary in this case. let mut dolly: Sheep = Animal::new("Dolly"); // TODO ^ Try removing the type annotations. dolly.talk(); dolly.shear(); dolly.talk(); }
- Differentiate between definition and implementation
trait Animal {
// Associated function signature; `Self` refers to the implementor type.
fn new(name: &'static str) -> Self;
}
impl Animal for Sheep {
// `Self` is the implementor type: `Sheep`.
fn new(name: &'static str) -> Sheep {
Sheep { name: name, naked: false }
}
}
- Default trait methods can be overridden
- Type annotation is necessary here
Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
--> src/main.rs:62:9
|
62 | let mut dolly = Animal::new("Dolly");
| ^^^^^^^^^
...
65 | dolly.talk();
| ----- type must be known at this point
|
help: consider giving `dolly` an explicit type
|
62 | let mut dolly: _ = Animal::new("Dolly");
| +++
For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` due to previous error