04 · Structs
struct groups named fields into a single type. Methods are added in an impl block and take &self for read access or &mut self for mutation. Structs are stack-allocated by default — no hidden heap unless you opt in with !alloc.
struct Point { x: f32, y: f32,}
impl Point { // Constructor — associated function, no self. fn new(x: f32, y: f32) -> Point { Point { x, y } }
// Method — borrows self immutably. fn distance_from_origin(&self) -> f32 { (self.x * self.x + self.y * self.y).sqrt() }
// Method — mutates self. fn translate(&mut self, dx: f32, dy: f32) { self.x += dx; self.y += dy; }}
fn main() !io { let mut p = Point::new(3.0, 4.0); println!("distance = {}", p.distance_from_origin());
p.translate(1.0, 0.0); println!("after translate: ({}, {})", p.x, p.y);}Output
Section titled “Output”distance = 5after translate: (4, 4)What the compiler sees
Section titled “What the compiler sees”Field access on &self is read-only — any attempt to mutate through a shared borrow is a compile error. The Point { x, y } shorthand in the constructor works when the local variable name matches the field name. Struct layout is deterministic and guaranteed stable across compilations for FFI use.
Next → 05 · Enums and Match