Trait Basics
In this page:
trait Name {
fn method(&self) -> ReturnType;
}
impl Name for Type {
fn method(&self) -> ReturnType {
// body
}
}
Defining a Trait
The trait keyword defines a set of method signatures that any implementing type must provide, describing shared behavior without dictating how it's stored.
Example: Defining a Trait
// Define a trait `Greet` describing shared behavior
trait Greet {
// Define the function `greet` taking `&self` and returning a `String;`
fn greet(&self) -> String;
}
// Define a struct `Person` to group related fields together
struct Person {
name: String,
}
// Implement the `Greet` trait for `Person`
impl Greet for Person {
// Define the function `greet` taking `&self` and returning a String
fn greet(&self) -> String {
format!("Hello, my name is {}", self.name)
}
}
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `p`, set to `Person { name: String::from("Ada") }`
let p = Person { name: String::from("Ada") };
// Print "{}" to the console, substituting in `p.greet()` (with a trailing newline)
println!("{}", p.greet());
}
Login to try C/C++/Java/PHP code in the editor
Implementing a Trait for Multiple Types
The same trait can be implemented for several unrelated types, each providing its own version of the required behavior.
Example: Implementing a Trait for Multiple Types
// Define a trait `Greet` describing shared behavior
trait Greet {
// Define the function `greet` taking `&self` and returning a `String;`
fn greet(&self) -> String;
}
// Define a struct `Robot` to group related fields together
struct Robot;
// Implement the `Greet` trait for `Robot`
impl Greet for Robot {
// Define the function `greet` taking `&self` and returning a String
fn greet(&self) -> String {
String::from("BEEP BOOP HELLO")
}
}
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `r`, set to `Robot`
let r = Robot;
// Print "{}" to the console, substituting in `r.greet()` (with a trailing newline)
println!("{}", r.greet());
}
Login to try C/C++/Java/PHP code in the editor
A Type Implementing Multiple Traits
A single type can implement as many different traits as needed, each contributing a different piece of behavior to that type.
Example: A Type Implementing Multiple Traits
// Define a trait `Greet` describing shared behavior
trait Greet {
// Define the function `greet` taking `&self` and returning a `String;`
fn greet(&self) -> String;
}
// Define a trait `Farewell` describing shared behavior
trait Farewell {
// Define the function `farewell` taking `&self` and returning a `String;`
fn farewell(&self) -> String;
}
// Define a struct `Person` to group related fields together
struct Person {
name: String,
}
// Implement the `Greet` trait for `Person`
impl Greet for Person {
// Define the function `greet` taking `&self` and returning a String
fn greet(&self) -> String {
format!("Hi, {}", self.name)
}
}
// Implement the `Farewell` trait for `Person`
impl Farewell for Person {
// Define the function `farewell` taking `&self` and returning a String
fn farewell(&self) -> String {
format!("Bye, {}", self.name)
}
}
// Entry point: execution of the program starts here
fn main() {
let p = Person { name: String::from("Lee") };
println!("{}", p.greet());
println!("{}", p.farewell());
}
Login to try C/C++/Java/PHP code in the editor
Calling Trait Methods Through the Trait
Once a trait is implemented for a type, its methods are called using ordinary dot syntax, exactly like any other method, as long as the trait is in scope.
Example: Calling Trait Methods Through the Trait
// Define a trait `Area` describing shared behavior
trait Area {
// Define the function `area` taking `&self` and returning a `f64;`
fn area(&self) -> f64;
}
// Define a struct `Square` to group related fields together
struct Square {
side: f64,
}
// Implement the `Area` trait for `Square`
impl Area for Square {
// Define the function `area` taking `&self` and returning a floating-point number
fn area(&self) -> f64 {
self.side * self.side
}
}
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `sq`, set to `Square { side: 4.0 }`
let sq = Square { side: 4.0 };
// Print "Area: {}" to the console, substituting in `sq.area()` (with a trailing newline)
println!("Area: {}", sq.area());
}
Login to try C/C++/Java/PHP code in the editor
- Forgetting to bring a trait into scope with
usebefore calling its methods on a type, even if the impl exists elsewhere. - Confusing a trait definition with a struct -- traits describe shared behavior, they do not themselves hold data.
- Implementing a trait's method with a different signature than the trait declares, which fails to compile.
- A trait defines a set of method signatures that implementing types agree to provide.
impl TraitName for TypeName { ... }provides the actual behavior for a specific type.- A single type can implement multiple different traits.
- Traits enable shared behavior across otherwise unrelated types, similar to interfaces in other languages.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: