Rust Structs
Real things have several properties. A student has a name, a roll number and marks. A book has a title, an author and a number of pages. A struct (short for structure) lets you create your own type that groups these properties together under clear names. It is like designing a form with labelled boxes, and then filling in as many copies of the form as you need.
Defining and using a struct
struct Student {
name: String,
roll_number: u32,
marks: f64,
}
fn main() {
let asha = Student {
name: String::from("Asha"),
roll_number: 12,
marks: 91.5,
};
println!("{} (roll {}) scored {}", asha.name, asha.roll_number, asha.marks);
}Asha (roll 12) scored 91.5
The definition, with struct, describes the shape: the names of the fields and their types. It is written outside main. Then Student { ... } creates an actual student, called an instance. You read a field with a dot: asha.name.
Struct names use CamelCase, with a capital letter for each word, like Student or BankAccount. That makes them easy to tell apart from variables.
Changing fields
To change a field, the whole instance must be mut. Rust does not let you mark only some fields as changeable:
struct Counter {
label: String,
value: u32,
}
fn main() {
let mut visits = Counter { label: String::from("Visitors"), value: 0 };
visits.value += 1;
visits.value += 1;
println!("{}: {}", visits.label, visits.value);
}Visitors: 2
A function that builds a struct
It is common to write a function that creates an instance. When a parameter has the same name as a field, you can write the name once; this is the field init shorthand:
struct Book {
title: String,
pages: u32,
}
fn new_book(title: &str, pages: u32) -> Book {
Book { title: title.to_string(), pages }
}
fn main() {
let books = vec![new_book("The Hobbit", 310), new_book("Matilda", 240)];
for b in &books {
println!("{} has {} pages", b.title, b.pages);
}
}The Hobbit has 310 pages Matilda has 240 pages
Printing a struct with Debug
println!("{}", asha) does not work for your own structs, because Rust cannot guess how you would like a student to look. But you can ask Rust to write a programmer's view for you with #[derive(Debug)] above the struct, and then print it with {:?}, or {:#?} for a tidier, multi-line view:
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 3, y: 7 };
println!("{:?}", p);
println!("Distance from the corner: {}", p.x + p.y);
}Point { x: 3, y: 7 }
Distance from the corner: 10derive asks the compiler to write some standard code for your type automatically. You will see it a lot, with other abilities such as Clone and PartialEq.
Practice exercises
- Make a
Moviestruct with a title, a year and a rating, create two movies and print them. - Write
fn older(a: &Person, b: &Person) -> &strthat returns the name of the older person. - Add
#[derive(Debug)]to one of your structs and print it with{:#?}.