Rust for beginners — Part 9 — Struct

Manikandan SP
6 min readMar 6, 2022

--

Let’s look into what is Struct and how we can use it in Rust lang in this section

Note: Kindly have a look into the previous section of tutorial to understand about &str in rust

Previous section: https://medium.com/@manikandan96372/rust-for-beginners-part-8-str-6ce56c02ca88

Struct

Struct is another type in rust that is composed of one or more than one types or a collection of different types.

If you want describe about just one attribute like a name or age or any other factor you can use types like string, integer etc. but what if you have a scenario where the attribute you want to discuss about requires more than one type like defining the attributes of a person or an animal or anything that has multiple characteristics to be discussed ?

Then your go-to person would be struct

Let’s consider a scenario of describing about a car, the following snippet shows how it should be defined using struct

fn main() {  struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
}

Struct in rust is created using the keyword struct followed by the name of the struct and a set of curly braces.

Inside the curly braces you can create different fields of your struct using various types in rust.

In the above we are adding the fields that describes a car using string type for car’s brand and model name, unsigned integer of 64 bit type to add price field and unsigned integer of 8 bit type to add mileage field.

Looks like you have already seen this somewhere right ? Yes it might look like your classes and objects in other programming languages like Javascript

Let’s see how we can instantiate a struct

fn main() { struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
let car = Car {
brand: String::from("Toyota"),
model: String::from("Corolla Altis"),
price: 2000000,
mileage: 20
};
}

In the above example, variable name “car” holds the instance of the struct with its certain set of fields with values defined to it like “Toyota” as brand, 20 as mileage etc.

Note: You have to always define every field in your structure element, if you miss any fields while instantiating it, your compiler would throw an error saying that you have a missing field from structure.

Let’s look into how we can access the fields of struct

The following code snippet shows how to access the brand name of your car

fn main() { struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
let car = Car {
brand: String::from("Toyota"),
model: String::from("Corolla Altis"),
price: 2000000,
mileage: 20
};
println!("{}", car.brand);}

The above code snippet on execution would provide the following output

Toyota

For accessing fields of struct you have specify the variable name followed by a dot (.) operator followed by your field name, that’s how you could access your struct fields.

We understood on how to create and access struct variables, now let’s look into how we can implement methods to struct that could be utilized outside.

Impl

Impl is the keyword using which we can define implementation methods for our struct variable.

Let’s consider a scenario where we want to print details of our car, the following code snippet shows how to achieve that using Impl

fn main() { struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
impl Car { fn print_car_details(&self) {
println!("{} {} {} {}", self.brand, self.model, self.price, self.mileage);
}
} let car = Car {
brand: String::from("Toyota"),
model: String::from("Corolla Altis"),
price: 2000000,
mileage: 20
};
car.print_car_details();}

The above code snippet on execution would give the following output

Toyota Corolla Altis 2000000 20
  1. If you want to implement methods to your struct variable, use Impl keyword followed by the name of your struct, in this case it is “Car”.
  2. Followed by a set of curly braces, inside which you can define your methods, which in this case is your “print_car_details”.
  3. The thing to be considered here is when you instantiate a struct variable you are defining the fields inside it but how the implementation methods of your struct will know which instance’s struct field that it should print ?
  4. That’s why “&self” is passed as an argument to your implementation method.
  5. &self is the reference to instance of the struct variable by which the implementation methods are called.
  6. By using &self the implementation methods will know from which instance that it should access the fields.
  7. When utilizing the implementation method, we should use the struct variable “car” followed by the dot(.) operator followed by the necessary implementation method which is “print_car_details” here.

This is how you can implement methods to your struct

Let’s look into how we can mutate the struct fields

Our situation is that we have to implement a new method that adds 5 to the existing mileage, when we invoke that method your current car instance’s mileage field should have an added value of 5 to it.

The following code shows how we can create change_mileage implementation method

fn main() { struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
impl Car { fn print_car_details(&self) {
println!("{} {} {} {}", self.brand, self.model, self.price, self.mileage);
}
fn change_mileage(&self) {
self.mileage = self.mileage + 5;
}
} let car = Car {
brand: String::from("Toyota"),
model: String::from("Corolla Altis"),
price: 2000000,
mileage: 20
};
car.change_mileage(); car.print_car_details();}

The above code snippet on execution would give the following error

The above error clearly states that the &self reference that you are passing to your implementation method is not a mutable reference.

So you cannot modify a struct field using an immutable reference

Let’s change the &self reference to a mutable one

fn main() { struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
impl Car { fn print_car_details(&self) {
println!("{} {} {} {}", self.brand, self.model, self.price, self.mileage);
}
fn change_mileage(&mut self) {
self.mileage = self.mileage + 5;
}
} let car = Car {
brand: String::from("Toyota"),
model: String::from("Corolla Altis"),
price: 2000000,
mileage: 20
};
car.change_mileage(); car.print_car_details();}

The above code snippet on execution would give the following error

But wait, we have changed our &self to &mut self right, then why it is throwing an error ?

Because the instance of car which we are creating here is not a mutable one, so we have change that also to a mutable one as follows

fn main() {  struct Car {
brand: String,
model: String,
price: u64,
mileage: u8
}
impl Car { fn print_car_details(&self) {
println!("{} {} {} {}", self.brand, self.model, self.price, self.mileage);
}
fn change_mileage(&mut self) {
self.mileage = self.mileage + 5;
}
} let mut car = Car {
brand: String::from("Toyota"),
model: String::from("Corolla Altis"),
price: 2000000,
mileage: 20
};
car.change_mileage(); car.print_car_details();}

The above code snippet on execution would give the following output

Toyota Corolla Altis 2000000 25

Now we are getting a changed mileage(25 instead of 20) after calling the equivalent implementation method for it.

This is how we can utilize struct in rust.

Let’s look into how we can use enum in rust in the next section.

--

--