TL;DR
- Trait = interface/behavior contract. Generics = write once, work for many types.
impl Trait for Type to implement. where clauses for complex bounds.
- Common traits:
Display, Debug, Clone, Default, Iterator, From/Into.
Traits
trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn preview(&self) -> String {
format!("{}...", &self.summarize()[..20])
}
}
struct Article { title: String, body: String }
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, &self.body[..50])
}
}
Generics
// Generic function
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut max = &list[0];
for item in list { if item > max { max = item; } }
max
}
// Generic struct
struct Pair<T> { first: T, second: T }
// Trait bound syntax options:
fn print_it(item: &impl Summary) { ... } // sugar
fn print_it<T: Summary>(item: &T) { ... } // explicit
fn print_it<T>(item: &T) where T: Summary { ... } // where clause
Derive-able Traits
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
struct Config {
port: u16,
host: String,
}
| Trait |
What it gives you |
Debug |
{:?} formatting |
Clone |
.clone() deep copy |
PartialEq |
== comparison |
Hash |
Usable as HashMap key |
Default |
Config::default() |
Serialize/Deserialize |
serde JSON/TOML/etc |