Traits
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.
1. struct Sheep { naked: bool, name: &'static str }
3. trait Animal {
4. // Static method signature; `Self` refers to the implementor type.
5. fn new(name: &'static str) -> Self;
7. // Instance method signatures; these will return a string.
8. fn name(&self) -> &'static str;
9. fn noise(&self) -> &'static str;
11. // Traits can provide default method definitions.
12. fn talk(&self) {
13. println!("{} says {}", self.name(), self.noise());
14. }
15. }
17. impl Sheep {
18. fn is_naked(&self) -> bool {
19. self.naked
20. }
22. fn shear(&mut self) {
23. if self.is_naked() {
24. // Implementor methods can use the implementor's trait methods.
25. println!("{} is already naked...", self.name());
26. } else {
27. println!("{} gets a haircut!", self.name);
29. self.naked = true;
30. }
31. }
32. }
34. // Implement the `Animal` trait for `Sheep`.
35. impl Animal for Sheep {
36. // `Self` is the implementor type: `Sheep`.
37. fn new(name: &'static str) -> Sheep {
38. Sheep { name: name, naked: false }
39. }
41. fn name(&self) -> &'static str {
42. self.name
43. }
45. fn noise(&self) -> &'static str {
46. if self.is_naked() {
47. "baaaaah?"
48. } else {
49. "baaaaah!"
50. }
51. }
53. // Default trait methods can be overridden.
54. fn talk(&self) {
55. // For example, we can add some quiet contemplation.
56. println!("{} pauses briefly... {}", self.name, self.noise());
57. }
58. }
60. fn main() {
61. // Type annotation is necessary in this case.
62. let mut dolly: Sheep = Animal::new("Dolly");
63. // TODO ^ Try removing the type annotations.
65. dolly.talk();
66. dolly.shear();
67. dolly.talk();
68. }
