Trait/Interface in Rust
Interface/class in Rust(declared with keyword trait) having
Virtual Functions(not pure Virtual)
declared or defined inside it. These functions are
implemented(overridden) on type.
A trait is a way to define shared behavior across different data types
// 1. Define the trait (the shared behavior)
trait Speak {
fn make_sound(&self); // Method signature with no body yet
}
struct Dog;
struct Cat;
// 2. Implement the trait for the Dog
impl Speak for Dog {
fn make_sound(&self) {
println!("Woof!");
}
}
// 3. Implement the same trait for the Cat
impl Speak for Cat {
fn make_sound(&self) {
println!("Meow!");
}
}
fn main() {
let dog = Dog;
let cat = Cat;
// Both types can use the exact same method name
dog.make_sound(); // Prints: Woof!
cat.make_sound(); // Prints: Meow!
}
Usage of Traits
Once a trait is defined, you can write generic functions that accept any
type, as long as it implements that trait:
// This function doesn't care if you pass a Dog or a Cat,
// as long as it is an animal that can Speak!
fn animal_talk(animal: &impl Speak) {
animal.make_sound();
}
Rust Lib provided Traits
Using Traits
Passing trait as argument to function
|
Returning trait from function
|
Trait Bound (Same as C++20 Concepts)
Rule we put on a function or structure that tells the Rust compiler: "This function should accept a data type, and the data type should implement this specific trait."
|
Alternative Syntax: The where Clause When you start adding multiple trait bounds, the <T: Area> syntax can get messy. Rust provides a cleaner way to write trait bounds using a where clause at the end of the function signature. These two lines mean the exact same thing to the compiler, but the second one is often easier to read:
|
Taking 2 or more Traits (using +)
use std::fmt::Display;
trait Area {
fn get_area(&self) -> f64;
}
struct Square { side:f64 }
impl Area for Square {
fn get_area(&self) -> f64 {
self.side * self.side
}
}
impl Display for Square {
fn fmt (&self, f: &mut std::fmt::Formatter <'_>) -> std::fmt::Result {
write!(f, "Square with side length {}", self.side)
}
}
// This function takes 2 traits
fn print_area <T> (a:T)
where
T: Area + Display
{
println!("{}", a);
println!("area: {}", a.get_area());
}
fn main() {
let sq = Square {side: 4.0};
print_area(sq);
}