A trait in Rust is similar to an interface in other programming languages. It defines a set of methods that a type must implement in order to use and interact with other code that expects those methods to be available.
Traits are defined using the ‘trait‘ keyword followed by the name of the trait and the list of method signatures that should be part of that trait. Here is an example:
trait Growable {
fn grow(&mut self);
fn is_growing(&self) -> bool;
}
In this example, we define a ‘Growable‘ trait that requires two methods to be implemented: ‘grow‘ and ‘is_growing‘. The ‘grow‘ method takes a mutable reference to a ‘self‘ object and has no return value, while the ‘is_growing‘ method takes an immutable reference to a ‘self‘ object and returns a boolean value.
To implement a trait for a struct or enum, we use the ‘impl‘ keyword followed by the name of the trait and the implementation block. Here is an example:
struct Plant {
height: f32,
is_alive: bool,
}
impl Growable for Plant {
fn grow(&mut self) {
self.height += 0.1;
}
fn is_growing(&self) -> bool {
self.is_alive
}
}
In this example, we implement the ‘Growable‘ trait for the ‘Plant‘ struct, which means we must provide an implementation for both the ‘grow‘ and ‘is_growing‘ methods. The ‘grow‘ method simply increments the ‘height‘ field of the ‘Plant‘, while the ‘is_growing‘ method returns the value of the ‘is_alive‘ field of the ‘Plant‘.
Once a type implements a trait, it can be used with any code that expects that trait, allowing for easy composition and reuse of functionality across different types.