In Rust we often want to group together some data and pass it to other functions for easier use. A struct
can be used for this purpose.
With structs, we can have multiple fields. And we can add more fields (or remove them) without updating all references to the struct
. This makes programs more maintainable.
In this example we have a struct
called Info, and it contains a Vec
and an usize
. We initialize and use the struct
in the program.
struct
and add 2 Strings to the vector.struct
using the "items" vector we just created (the compiler figures out that the "items" name fills the field).struct
as an immutable reference to use_struct
. This function cannot modify the struct
, but can read its values.struct Info { items: Vec<String>, id: usize, } fn use_struct(info: &Info) { // Display some of the struct's fields. println!("LEN = {} ID = {}", info.items.len(), info.id); } fn main() { // Step 1: Create vector to place in new struct. let mut items = vec![]; items.push(String::from("one")); items.push(String::from("two")); // Step 2: Create struct with items and id. let info = Info { items, id: 0 }; // Step 3: Pass struct by reference to function. use_struct(&info); }LEN = 2 ID = 0
struct
referenceWhat if we want to change a struct
's fields in a function call? We can use a mutable reference to pass the struct
to the function.
update_house
function can modify fields on the struct
. It increases the "boards" field of the House.struct House { boards: usize, } fn update_house(house: &mut House) { // Add boards to the house, which is behind a mutable reference. house.boards += 2; } fn main() { let mut house = House { boards: 0 }; // Pass a mutable reference to the struct to a function so it can be modified. update_house(&mut house); println!("BOARDS = {}", house.boards); }BOARDS = 2
struct
It is possible, and common, to nest structs in Rust. The structs are combined into one region of memory when the program runs, so there is no performance loss.
struct
inside the House struct
. This could make code clearer that operates on a Door, but not a House.struct House { boards: usize, door: Door, } struct Door { color: String, width: usize, } fn main() { // Create a struct with a nested field struct (Door). let mut house = House { boards: 0, door: Door { color: String::from("red"), width: 10, }, }; println!("DOOR COLOR = {}", house.door.color) }DOOR COLOR = red
It is possible create a struct
without specifying all its fields. We can do this by specifying an existing struct
to update the current struct
with.
struct
by updating it with a const
struct
EMPTY. This provides default values for the fields.struct Test { one: usize, two: usize, three: usize, } const EMPTY: Test = Test { one: 1, two: 2, three: 3, }; fn main() { // Part 1: Use struct update syntax. let t = Test { ..EMPTY }; println!("{} {} {}", t.one, t.two, t.three); // Part 2: Update the empty struct with one new value. let t = Test { three: 900, ..EMPTY }; println!("{} {} {}", t.one, t.two, t.three); }1 2 3 1 2 900
Tuple
struct
With a tuple struct
, we specify a struct
that does not contain any named fields, but is used like a tuple. The struct
type name can be used to reference the tuple.
struct Yard(usize); struct Street(usize, u8); fn main() { let y = Yard(100); // The first field is accessed with 0. println!("{}", y.0); // Use a tuple struct with 2 fields (0 and 1). let s = Street(100, 5); println!("{} {}", s.0, s.1); }100 100 5
When developing programs, we often want to know what a struct
's contents are at a certain point. We can use println
with a struct
that has the Debug trait on it.
struct
To reduce memory usage, we can place the packed attribute on a struct
. This only works on structs that do not contain heap-allocated references.
Structs are a core part of almost all Rust programs. We can initialize them, use nested structs, and pass them as immutable or mutable references to functions.