Crash Courses · Masters
Traits & Generics
Write reusable, type-safe abstractions without runtime cost
40 min read+175 XP on completionCert: Rust Crash Course
Tap any word in the text below to start reading from there.
Traits & Generics
Defining a Trait
trait Summary {
fn summarize(&self) -> String;
// Default implementation
fn preview(&self) -> String {
format!("Read more: {}", self.summarize())
}
}
struct Article {
title: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}...", self.title, &self.content[..50.min(self.content.len())])
}
}
fn main() {
let a = Article {
title: "Rust is fast".into(),
content: "Rust achieves performance without a garbage collector.".into(),
};
println!("{}", a.summarize());
println!("{}", a.preview()); // uses default implementation
}Generics with Trait Bounds
use std::fmt::Display;
// T must implement both Display and PartialOrd
fn largest<T: PartialOrd + Display>(list: &[T]) -> &T {
let mut biggest = &list[0];
for item in list {
if item > biggest {
biggest = item;
}
}
biggest
}
fn main() {
let numbers = vec![34, 50, 25, 100, 65];
println!("Largest: {}", largest(&numbers)); // 100
let chars = vec!['y', 'm', 'a', 'q'];
println!("Largest: {}", largest(&chars)); // y
}impl Trait (modern shorthand)
// In parameter position — accepts any type implementing Display
fn print_item(item: &impl Display) {
println!("{}", item);
}
// In return position — return some type implementing Iterator
fn make_counter(n: u32) -> impl Iterator<Item = u32> {
(0..n)
}Generic Structs
struct Pair<T> {
first: T,
second: T,
}
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.first >= self.second {
println!("First is larger: {}", self.first);
} else {
println!("Second is larger: {}", self.second);
}
}
}dyn Trait (Dynamic Dispatch)
Use Box<dyn Trait> when you need a collection of heterogeneous types:
fn make_shapes() -> Vec<Box<dyn Summary>> {
vec![
Box::new(Article { title: "A".into(), content: "...".into() }),
// Box::new(Tweet { ... }),
]
}Dynamic dispatch has a small runtime cost (vtable lookup) vs the zero-cost of generics (monomorphization). Use generics when you know the type at compile time; dyn when you need heterogeneous collections.
Reading progress
0% read
In this module
trait
Generic <T>
Trait bound
Monomorphization
0%