Rust Traits
Shared behavior and interfaces for types
🔗 What are Traits?
Traits define shared behavior that types can implement. They're like interfaces in other languages, allowing different types to share common functionality and enabling powerful abstractions.
trait Drawable {
fn draw(&self);
}
Trait Features
Method Signatures
Define required methods
trait Summary {
fn summarize(&self) -> String;
}
Default Implementations
Provide default behavior
trait Greet {
fn greet(&self) {
println!("Hello!");
}
}
Trait Bounds
Constrain generic types
fn process(item: T) {}
Trait Objects
Dynamic dispatch
Box
🔹 Defining and Implementing Traits
Create traits and implement them for different types:
// Define a trait
trait Animal {
fn name(&self) -> &str
fn sound(&self) -> &str
// Default implementation
fn speak(&self) {
println!("{} says {}", self.name(), self.sound());
}
}
// Implement for different types
struct Dog {
name: String,
}
struct Cat {
name: String,
}
impl Animal for Dog {
fn name(&self) -> &str {
&self.name
}
fn sound(&self) -> &str {
"Woof!"
}
}
impl Animal for Cat {
fn name(&self) -> &str {
&self.name
}
fn sound(&self) -> &str {
"Meow!"
}
// Override default implementation
fn speak(&self) {
println!("{} purrs and says {}", self.name(), self.sound());
}
}
fn main() {
let dog = Dog { name: String::from("Buddy") };
let cat = Cat { name: String::from("Whiskers") };
dog.speak();
cat.speak();
}
Output:
Buddy says Woof!
Whiskers purrs and says Meow!
Whiskers purrs and says Meow!
🔹 Trait Bounds
Use traits to constrain generic functions:
use std::fmt::Display;
trait Printable {
fn print(&self);
}
impl Printable for T {
fn print(&self) {
println!("Value: {}", self);
}
}
// Function with trait bound
fn print_twice(item: T) {
println!("First: {}", item);
println!("Second: {}", item.clone());
}
// Multiple trait bounds
fn compare_and_print(a: T, b: T)
where
T: Display + PartialOrd + Clone,
{
if a > b {
println!("{} is greater than {}", a, b);
} else if a < b {
println!("{} is less than {}", a, b);
} else {
println!("{} equals {}", a, b);
}
}
fn main() {
print_twice(42);
print_twice("Hello".to_string());
compare_and_print(10, 5);
compare_and_print("apple", "banana");
}
Output:
First: 42
Second: 42
First: Hello
Second: Hello
10 is greater than 5
apple is less than banana
Second: 42
First: Hello
Second: Hello
10 is greater than 5
apple is less than banana
🔹 Trait Objects
Use traits for dynamic dispatch:
trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
}
struct Circle {
radius: f64,
}
struct Rectangle {
width: f64,
height: f64,
}
impl Shape for Circle {
fn area(&self) -> f64 {
3.14159 * self.radius * self.radius
}
fn perimeter(&self) -> f64 {
2.0 * 3.14159 * self.radius
}
}
impl Shape for Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
fn print_shape_info(shape: &dyn Shape) {
println!("Area: {:.2}", shape.area());
println!("Perimeter: {:.2}", shape.perimeter());
}
fn main() {
let shapes: Vec> = vec![
Box::new(Circle { radius: 5.0 }),
Box::new(Rectangle { width: 4.0, height: 6.0 }),
];
for (i, shape) in shapes.iter().enumerate() {
println!("Shape {}:", i + 1);
print_shape_info(shape.as_ref());
println!();
}
}
Output:
Shape 1:
Area: 78.54
Perimeter: 31.42
Shape 2:
Area: 24.00
Perimeter: 20.00
Area: 78.54
Perimeter: 31.42
Shape 2:
Area: 24.00
Perimeter: 20.00
🔹 Deriving Common Traits
Automatically implement common traits:
#[derive(Debug, Clone, PartialEq, PartialOrd)]
struct Person {
name: String,
age: u32,
}
#[derive(Debug, Copy, Clone, PartialEq)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let person1 = Person {
name: String::from("Alice"),
age: 30,
};
let person2 = person1.clone(); // Clone trait
println!("{:?}", person1); // Debug trait
println!("Are they equal? {}", person1 == person2); // PartialEq trait
let point1 = Point { x: 1, y: 2 };
let point2 = point1; // Copy trait (no move)
println!("Point 1: {:?}", point1);
println!("Point 2: {:?}", point2);
// Comparing people
let person3 = Person {
name: String::from("Bob"),
age: 25,
};
if person1 > person3 {
println!("{} is older than {}", person1.name, person3.name);
}
}
Output:
Person { name: "Alice", age: 30 }
Are they equal? true
Point 1: Point { x: 1, y: 2 }
Point 2: Point { x: 1, y: 2 }
Alice is older than Bob
Are they equal? true
Point 1: Point { x: 1, y: 2 }
Point 2: Point { x: 1, y: 2 }
Alice is older than Bob