Lesson 8
Structs
Define custom data types with structs, add methods with impl blocks, and use associated functions.
Defining Structs
Structs let you create custom data types by grouping related values together. Think of them like classes in other languages, but without inheritance. You define a struct with named fields, each with its own type.
struct User {
name: String,
age: u32,
}
Methods with impl
To add behavior to a struct, use an impl block. Methods take &self as their first parameter (like this in other languages). Use &self to read, &mut self to modify, or self to consume the struct.
Associated Functions
Functions inside impl that don't take self are called associated functions. They're called with :: syntax, like Rectangle::new(). You'll see these used as constructors all the time in Rust.
Try it
struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
// Associated function (constructor) -- no self parameter
fn new(width: f64, height: f64) -> Rectangle {
Rectangle { width, height }
}
// Method -- borrows self immutably
fn area(&self) -> f64 {
self.width * self.height
}
fn is_square(&self) -> bool {
self.width == self.height
}
fn describe(&self) {
println!(
"Rectangle: {:.1} x {:.1}, area = {:.1}, square = {}",
self.width,
self.height,
self.area(),
self.is_square()
);
}
// Method that takes mutable reference
fn scale(&mut self, factor: f64) {
self.width *= factor;
self.height *= factor;
}
}
fn main() {
// Create using the associated function
let mut rect = Rectangle::new(10.0, 5.0);
rect.describe();
println!("Area: {:.1}", rect.area());
// Mutate through a method
rect.scale(2.0);
println!("\nAfter scaling by 2x:");
rect.describe();
// Create a square
let square = Rectangle::new(7.0, 7.0);
square.describe();
// Direct struct creation also works
let tiny = Rectangle { width: 1.0, height: 1.0 };
tiny.describe();
}Challenge
Add a perimeter() method to the Rectangle struct that returns 2 * (width + height). Call it from main and print the result.
Previous: References & Borrowing
Next: Enums