Defining and implementing a trait
A trait is a named set of methods that a type promises to provide, like an interface in Java or TypeScript. You define it once, then write an impl Trait for Type block for each type that should have it. Any type can implement any number of traits, including types that were written long before the trait existed.
trait Summary {
fn author(&self) -> String; // required: no body
fn summarize(&self) -> String { // default method
format!("(Read more from {}...)", self.author())
}
}
struct Tweet {
user: String,
text: String,
}
struct Article {
title: String,
by: String,
}
impl Summary for Tweet {
fn author(&self) -> String {
format!("@{}", self.user)
}
fn summarize(&self) -> String { // overrides the default
format!("{}: {}", self.author(), self.text)
}
}
impl Summary for Article {
fn author(&self) -> String {
self.by.clone()
} // keeps the default summarize
}
fn main() {
let t = Tweet { user: String::from("rustlang"), text: String::from("1.0 is out") };
let a = Article { title: String::from("Traits"), by: String::from("Ada") };
println!("{}", t.summarize());
println!("{} {}", a.title, a.summarize());
}@rustlang: 1.0 is out
Traits (Read more from Ada...)Add a third type, Podcast { host: String }, and implement only author. Which summarize does it get?
A default method has a body in the trait, and can call the trait's required methods. Implementers get it for free and may override it. This is how the standard library gives you dozens of iterator methods once you write next (Module 09).
E0046: a required method is missing
trait Shape {
fn area(&self) -> f64;
fn name(&self) -> String;
}
struct Square(f64);
impl Shape for Square {
fn area(&self) -> f64 {
self.0 * self.0
}
}
fn main() {
println!("{}", Square(2.0).area());
}error[E0046]: not all trait items implemented, missing: `name`
--> main.rs:8:1
|
3 | fn name(&self) -> String;
| ------------------------- `name` from trait
...
8 | impl Shape for Square {
| ^^^^^^^^^^^^^^^^^^^^^ missing `name` in implementationAn impl Shape for Square is a promise to provide every method the trait declares without a body. name has no default, so the promise is broken.
Implement name, or give it a default body in the trait if most types would write the same thing.
trait Shape {
fn area(&self) -> f64;
fn name(&self) -> String;
}
struct Square(f64);
impl Shape for Square {
fn area(&self) -> f64 {
self.0 * self.0
}
fn name(&self) -> String {
String::from("square")
}
}
fn main() {
let s = Square(2.0);
println!("{} {}", s.name(), s.area());
}