Traits
A trait defines behavior a type promises to provide — Rust's answer to interfaces. Instead of inheritance between structs, you implement the same trait for different types, and write functions that accept anything satisfying it.
Defining and implementing a trait
trait Summary { fn summarize(&self) -> String; } struct Article { title: String, words: u32, } impl Summary for Article { fn summarize(&self) -> String { format!("{} ({} words)", self.title, self.words) } } fn main() { let post = Article { title: String::from("Rust 101"), words: 800 }; println!("{}", post.summarize()); }
Rust 101 (800 words)
trait Summary declares that anything implementing it must provide a summarize method with that exact signature — it's a contract, with no data of its own. impl Summary for Article is where Article actually fulfills that contract. Any number of unrelated structs can implement the same trait, each with its own version of summarize.
Accepting anything that implements a trait
fn print_summary(item: &impl Summary) { println!("Summary: {}", item.summarize()); } fn main() { let post = Article { title: String::from("Rust 101"), words: 800 }; print_summary(&post); }
Summary: Rust 101 (800 words)
&impl Summary as a parameter type means "a reference to anything that implements Summary" — print_summary doesn't care whether it's given an Article or some other struct entirely, only that .summarize() exists on it. This is how Rust achieves the same flexibility Java or C# get from interfaces, without needing struct inheritance at all.
Deriving common traits automatically
#[derive(Debug)] struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 3, y: 7 }; println!("{:?}", p); }
Point { x: 3, y: 7 }#[derive(Debug)] is an attribute that asks the compiler to generate a working Debug trait implementation for Point automatically, which is what makes {:?} — the format specifier you've already used on Vecs and other built-ins — work here too. Common derivable traits also include Clone (for .clone()), PartialEq (for ==), and Default; deriving them saves writing the boilerplate implementation by hand for the vast majority of straightforward structs.
for x in your_type), and formatting all work under the hood in Rust — std::ops::Add, Iterator, and Display are just traits like Summary above, implemented by the standard library's own types. Once traits click, a lot of what initially looks like special-cased language magic turns out to just be an ordinary trait implementation you could write yourself.Option and Result, and traits. Ownership is the idea that ties everything together — once it's second nature, the rest of Rust's rules mostly follow from wanting to protect it, and code that compiles tends to simply work.