Traits
A trait is essentially an interface. It defines functionality that can then be shared with other types.
Defining a trait
You do not have to provide a function body when defining a trait. If not, the implementation must be done on each type that inherits this trait. It is possible to define a default behavior and then later override it. Trait methods can also call other trait methods, even if they do not have default implementations. Those functions called without default implentations will then need to be defined in the inheriting type.
pub trait Summary {
fn summarize(&self) -> String;
}
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
pub trait Summary {
fn summarize_author(&self) -> String;
fn summarize(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}
Implementing a trait
To implement a trait, you use the impl <trait> for <struct>
syntax.
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
Traits as parameters
You can also use traits as you would types if you only want to call functions defined in the trait.
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// Or
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// With multiple traits
pub fn notify(item: &(impl Summary + Display)) {
// do something
}
// Or
pub fn notify<T: Summary + Display>(item: &T) {
// do something
}
// With where clause
fn some_function<T, U>(t: &T, u: &U) -> i32
where T: Display + Clone,
U: Clone + Debug
{
// do something
}
Returning types that implement traits
You can only use a trait as a return value if you are returning a single type.
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
retweet: false,
}
}