30 days of Rust - Day Ten - Traits
Ten days into the challenge and I must say I am growing at an exponential rate. I have always had a challenge with adopting new habits. Initially, the first couple of days are exciting and it's easy to be consistent. Then there is a period where things get hard, (e.g learning more abstract coding concepts such as Ownership in Rust), and then I start slacking. I can take a day off because I deserve a break. Next thing I know, it's been 2 months š without practicing the new habit.
This time, things are different. I am accountable. I intentionally decided to learn publicly š. Every single day, I have people waiting for my blog post to read at lunch time. This has so far been a very powerful motivator for me. Having a community. I can't afford to slip in public so I make sure that everyday I put in at least an hour, regardless of the circumstance.
You can drastically change your life in 6 months with just 1 hour a day of pure focus - Dan Koe
Read that again, until it makes sense.
Day 10 - Traits
A trait in Rust refers to functionality that a type can have in common with other types. If, like me, you come from a language such as Java you might think of them as Interfaces.
Creating a trait
To make this concept easy to grasp, let's think about it in the form of cars. All cars have common functionality such as change gear, speed up, slow down, turn on and off, refuel etc.
So let's implement a trait with just one method, refuel
. An electric car does not refuel the same way as a car that runs a petrol engine.
We use the trait
keyword in order to define a trait;
pub trait Car {
fn refuel(&self) -> String;
}
The above line creates a trait that can be used by other Types. The type which implements this trait will decide how they want to refuel, for as long as it returns a String.
Implementing the trait
In order to implement the trait, we will use the impl
keyword the same way we create methods for structs as seen here.
pub struct Tesla {
pub battery_capacity : u32,
}
impl Car for Tesla {
fn refuel(&self) -> String {
format!("Battery Charging {} kilowatt-hours...", self.battery_capacity)
}
}
pub struct Hilux {
pub fuel_tank_capacity : u32
}
impl Car for Hilux {
fn refuel(&self) -> String {
format!("Adding {} Liters of Petrol to fuel tank ā½ļø..." , self.fuel_tank_capacity)
}
}
Now the Car
trait has been implemented on both the Tesla
and Hilux
, we can make use of it in our main function call;
fn main(){
let van = Hilux {
fuel_tank_capacity: 60
};
let tesla = Tesla {
battery_capacity: 100
};
println!("{}", van.refuel());
println!("{}", tesla.refuel());
}
The code above outputs;
Adding 60 Liters of Petrol to fuel tank ā½ļø...
š Battery Charging 100 kilowatt-hours...
Default implementation
If ever we want to have a default behavior for our trait, we can do so by having the implementation inside the trait definition.
pub trait Car {
fn refuel(&self) -> String {
format!("refueling car")
}
}
We don't have to change anything else in our code. In order to override the default behavior we can just the standard impl
keyword with the new method like;
impl Car for Tesla {
fn refuel(&self) -> String {
format!("Battery Charging {} kilowatt-hours...", self.battery_capacity)
}
}
Using traits as parameters
We can also have functions which take in parameters of various types, for as long as they implement certain traits. For instance;
pub fn car_wash(car: &impl Car) {
println!("š¦ š ...")
}
The function car_wash
will take in any type for as long as it implements the Car
trait. We also have access to all the methods the Car
trait has defined.
Conclusion
Being able to share behavior between various types allows us to write even cleaner code. This also helps reduce the number of errors at runtime, compared to dynamically typed languages, we can verify that a type has certain behavior before it gets to the user at runtime. This is a concept I am still going to come back to as there is a lot to cover in such a short space of time. Thank you so much for spending a couple of minutes learning Rust with me. Please let me know on LinkedIn what programming language you're looking to learn next and why. Until next time. Peace āš¼