Rust Structs
In Rust, a struct is a custom data type. There are three types of structs in Rust: classic ‘C’ structs, tuple structs, and unit structs.
These three types of structs share many characteristics but have distinct differences and are optimized for different applications.
In this tutorial, we will cover how to declare and initialize a classic C struct. It’s helpful to start with a classic struct and then learn tuple structs and unit structs, which we can compare with classic structs. We’ll also learn how to access a value from a struct instance and modify a value of a mutable struct.
What Are Structs in Rust?
Structs are custom data types consisting of key-value pairs. Using a struct requires two steps:
- Declaring the struct.
- Initializing an instance of the struct.
The struct instance is a variable that we can work with. Once we have an instance, we can extract or modify the values of its’ key-value pairs.
Declaring a Struct
Structs are declared using the struct keyword. This creates a new, custom data type that we can create instances of.
In the example below, we are creating a new struct (a new data type) called StructName:
struct StructName {}
Rust Struct Naming Conventions
Naming structs: In Rust, structs use UpperCamelCase (also called PascalCase) for the struct name.
This means that the first letter of each word is capitalized, and words are not separated by any characters.
The body of the struct contains key-value pairs that are called fields. When declaring a struct, we need to include the name of each key, and the data type of the associated value.
When we later initialize a struct, the type of each value must match the type specified:
struct MyStruct{
key1: <type 1>,
key2: <type 2>,
key3: <type 3>,
}
Each line in the body of the struct is terminated using a comma (rather than the standard semicolon).
Let’s look at a real example:
struct Student {
name: String,
age: i32,
average: i32,
}
Initializing a Struct
We have declared a struct, which is like defining a new, compound data type with a key-value pair that we specified.
In order to make use of a struct, we need to initialize an instance of that struct. This creates a new compound variable of the struct type that we declared.
To initialize a struct, we use the let keyword followed by the name of the struct instance, i.e. the variable that we are creating. We tell Rust that our new variable has a data type of our struct using the assignment operator ‘=‘:
let my_name = StructName {}
The body of the instance code block must contain each key-value pair from the struct declaration, but this time we are actually assigning values that will be stored in memory.
let my_struct = MyStruct {
key1: <value 1>,
key2: <value 2>,
key3: <value 3>,
}
Let’s see this in practice using our Student example:
struct Student {
name: String,
age: i32,
average: i32,
}
let bill = Student {
name: "Bill".to_string(),
age: 61,
average: 83,
};
Note the 1:1 correspondence between the key-value pairs in the declaration and those in the initialization. These can be in any order but it can be easier to read if we keep them in the same order if possible.
Accessing a Value From a Struct
Now that we have a struct declared and initialized, we can extract the value of any of the key-value pairs (i.e. get the value of a key) using dot notation:
my_struct.<key name>
For example:
struct Student {
name: String,
age: i32,
average: i32,
}
let bill = Student {
name: "Bill".to_string(),
age: 61,
average: 83,
};
println!("Name: {}", bill.name);
println!("Age: {}", bill.age);
println!("Average: {}", bill.average);
Standard Output:
Name: Bill
Age: 61
Average: 83
Updating a Mutable Struct
Struct instances are immutable by default. Like other variables, a struct instance can be made mutable using the mut keyword:
let mut my_struct = StructName {}
The key values for the instance can be updated using the dot notation and assignment operator:
my_struct.<key name> = <new value>;
In the following example, we want to update Bill’s age:
struct Student {
name: String,
age: i32,
average: i32,
}
let mut bill = Student {
name: "Bill".to_string(),
age: 61,
average: 83,
};
println!("Original Age: {}", bill.age);
bill.age = 62;
println!("New Age: {}", bill.age);
Standard Output:
Original Age: 61
New Age: 62
This permanently modifies the struct instance.