30 days of Rust - Day three - Structure
Day 3 - Structs
So far, I've just been working with variables and functions that are scattered around everywhere. This makes it a bit challenging for other people to read our code as it grows bigger πΎ. There's a saying my previous manager used to say to me a lot, that goes;
Code that works together, stays together.
It was way ahead of its time for me. I never really appreciated it enough until I got to work in Java that forces you into OOP (Object Oriented Programming). It allows us to better group related data and functions (called methods). This then gives us the power to create our own, new data types.
Life without Structure
To demonstrate this, let's see an example without the use of structure. Let's say on a friday evening you go for dinner with 3 friends at 012 Lifestyle
. You have a platter costing R500 and one cocktail each costing R80. Now it's time to split the bill equally. Disaster π±. Don't worry I'll help you out π. Let's calculate the total including the tip
and cost per person
.
fn main(){
let prices_of_items_ordered = [500.0, 80.0, 80.0, 80.0];
let tip = 0.1; //10%
let num_of_people =3;
let bill = calculate_total_with_tip(&prices_of_items_ordered, &tip);
let contribution_per_person = cost_per_person(&bill, num_of_people);
println!("Each person must pay R{}", contribution_per_person);
}
fn calculate_total_with_tip(list_items: &[f32], tip: &f32) -> f32{
let mut total = 0.0;
for item in list_items {
total += item;
}
total = total + (total * tip);
total
}
fn cost_per_person(total: &f32, num_of_people: i8) -> f32{
total / f32::from(num_of_people)
}
Output:
Each person must pay R271.33
So the program above works and everyone goes home happy, but it's more like Spaghetti code.
Life with Structure
Let's make our code more readable by introducing Structs
to it.
struct Table {
prices_of_items_ordered: [f32; 4],
tip: f32,
num_of_people: i8
}
impl Table {
fn calculate_total_with_tip(&self) -> f32{
let mut total = 0.0;
for item in self.prices_of_items_ordered {
total += item;
}
total = total + (total * self.tip);
total
}
fn cost_per_person(&self, total: &f32) -> f32{
total / f32::from(self.num_of_people)
}
}
fn main(){
let our_table = Table {
prices_of_items_ordered : [500.0, 80.0, 80.0, 80.0],
tip : 0.1,
num_of_people :3
};
let total_bill = our_table.calculate_total_with_tip();
let contribution_per_person = our_table.cost_per_person( &total_bill);
println!("Each person must pay R{}", contribution_per_person);
}
Now that's more like it π¦.
So we created a Table
struct (similar to a Class in OOP). Now the Table has the properties prices_of_items_ordered, tip and num_of_people
.
struct Table {
prices_of_items_ordered: [f32; 4],
tip: f32,
num_of_people: i8
}
We use these values in order to calculate our calculate_total_with_tip
and cost_per_person
, which are now called methods instead of functions because they now belong to the Table struct. In order to create methods, we use the impl
keyword followed by the name of the struct. Thereafter we move the functions inside the brackets, which looks like this.
impl Table {
fn calculate_total_with_tip(&self) -> f32{
let mut total = 0.0;
for item in self.prices_of_items_ordered {
total += item;
}
total = total + (total * self.tip);
total
}
fn cost_per_person(&self, total: &f32) -> f32{
total / f32::from(self.num_of_people)
}
}
Next up we create an instance of Table called our_table;
let our_table = Table {
prices_of_items_ordered : [500.0, 80.0, 80.0, 80.0],
tip : 0.1,
num_of_people :3
};
Once we create our_table
, it is now easy to calculate the total by calling the methods;
let total_bill = our_table.calculate_total_with_tip();
let contribution_per_person = our_table.cost_per_person( &total_bill);
Bonus
We can also change the values of the properties in our struct.
Let's say we have an extra person join the party πΊπΌ. So now we're 4 instead of 3.
Firstly we'd need to make our_table
mutable (changeable) with the mut
keyword.
let mut our_table = Table {
prices_of_items_ordered : [500.0, 80.0, 80.0, 80.0],
tip : 0.1,
num_of_people :3
};
Lastly, we use dot notation to change the properties we want;
// 4 people now
our_table.num_of_people = 4;
That's all you have to doπ . And Now our output is
Each person must pay R203.5
Conclusion
Structs are an important part of rust as they allow us to group data much better in more meaningful ways. They allow us to create custom data types of almost anything you can imagine(Car, House, Person, etc.)
This also helps us reduce our chances of introducing bugs to our program.
Thank you so much for taking time out of your day to learn with me π¨π½βπ». Please give suggestions as to how I can make this blog better and hit me up if you're joining the challenge π.