Rust Traits
Overview
A trait defines shared behavior for multiple types.
If a type implements a trait, that type promises to provide the methods required by the trait. This makes traits the core mechanism for abstraction and polymorphism in Rust.
trait Speak {
fn speak(&self);
}
In practice, traits are used for:
- shared APIs across unrelated types
- generic constraints
- static dispatch with
impl Traitor trait bounds - dynamic dispatch with trait objects such as
dyn Trait
Define a Trait
Traits define method signatures and may also provide default implementations.
trait Summary {
fn summarize(&self) -> String;
fn short_summary(&self) -> String {
String::from("(summary omitted)")
}
}
- Required methods must be implemented by every type that implements the trait.
- Default methods can be reused as-is or overridden.
Implement a Trait for a Type
Use an impl <Trait> for <Type> block to implement the trait.
struct Article {
title: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("Article: {}", self.title)
}
}
You can then call the trait methods on the value:
let article = Article {
title: String::from("Traits in Rust"),
};
println!("{}", article.summarize());
println!("{}", article.short_summary());
Use a Trait in Function Parameters
When a function should accept any type that implements a trait, constrain the parameter with that trait.
trait Speak {
fn speak(&self);
}
fn talk(item: &impl Speak) {
item.speak();
}
This means talk can receive any borrowed value whose type implements Speak.
The equivalent generic form is:
fn talk<T: Speak>(item: &T) {
item.speak();
}
Use impl Trait when you want concise syntax. Use an explicit type parameter such as T: Speak when the type relationship matters elsewhere in the signature.
Trait Bounds
Trait bounds restrict generic types.
fn notify<T: Summary>(item: &T) {
println!("{}", item.summarize());
}
You can require multiple traits:
fn notify<T: Summary + Clone>(item: &T) {
let cloned = item.clone();
println!("{}", cloned.summarize());
}
For more complex signatures, a where clause is often easier to read:
fn compare_and_print<T, U>(left: &T, right: &U)
where
T: Summary,
U: Summary,
{
println!("{}", left.summarize());
println!("{}", right.summarize());
}
impl Trait
impl Trait is commonly used for parameters and return values.
Parameter position:
fn render(item: &impl Summary) {
println!("{}", item.summarize());
}
Return position:
fn make_article() -> impl Summary {
Article {
title: String::from("Rust Trait Guide"),
}
}
For return types, impl Trait means the function returns one concrete type that implements the trait. It does not mean the function can return different concrete types from different branches unless they resolve to the same concrete type.
Trait Objects with dyn Trait
Trait objects enable dynamic dispatch.
fn render_all(items: Vec<Box<dyn Summary>>) {
for item in items {
println!("{}", item.summarize());
}
}
Use this when you need to store or pass multiple different concrete types behind a shared trait interface at runtime.
Common forms:
&dyn TraitBox<dyn Trait>Arc<dyn Trait>
Trait objects are useful when the exact concrete type is not known until runtime, but they introduce dynamic dispatch and object-safety constraints.
Static Dispatch vs Dynamic Dispatch
Use static dispatch when possible:
T: Traitimpl Trait
This is usually the default choice because it is simpler for performance and preserves concrete type information at compile time.
Use dynamic dispatch when runtime flexibility matters more:
&dyn TraitBox<dyn Trait>
This is useful when a collection must hold multiple concrete types that all implement the same trait.
Common Standard Traits
Rust code frequently uses standard traits such as:
DebugDisplayCloneCopyDefaultPartialEqEqOrdIterator
These traits define common behavior that many library APIs depend on.
When to Split This Page
Keep this page as the main overview for Rust traits. If the topic grows significantly, split it into focused pages such as:
- trait bounds
impl Trait- trait objects
- object safety
- associated types
That keeps /docs/language/rust/trait.mdx as the entry point while moving deeper material into dedicated pages.