Skip to content

Structs

A struct groups related fields under a single named type. Each field has a name and a type.

struct Point {
x: f64,
y: f64,
}

You create an instance by providing values for every field.

let p = Point { x: 3.0, y: 4.0 };

Access fields with dot notation: p.x, p.y. Fields are private to the module by default; prefix them with pub to expose them.

When you want a new instance that shares most fields with an existing one, use the .. update syntax:

let p2 = Point { x: 10.0, ..p };

This copies the remaining fields (y in this case) from p. Note that fields implementing Copy are copied; fields that are Move-only are moved.

Add behaviour to a struct in an impl block. Each method takes the receiver as its first parameter.

impl Point {
fn distance_from_origin(&self) -> f64 {
(self.x * self.x + self.y * self.y).sqrt()
}
}

Functions inside impl that do not take a self parameter are called associated functions. They are called with :: syntax. The conventional name for a constructor is new:

impl Point {
fn new(x: f64, y: f64) -> Self {
Point { x, y }
}
}
let p = Point::new(1.0, 2.0);

Self inside an impl block is an alias for the type being implemented.

Tuple structs give a name to an unnamed sequence of fields. They are useful as lightweight type-safe wrappers.

struct Color(u8, u8, u8);
let red = Color(255, 0, 0);
println!("{}", red.0); // access by index

Unlike a plain tuple, a Color and a Point with the same field types are distinct types — the compiler will reject mixing them up.

#[derive(Debug)]
struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Rectangle { width, height }
}
fn area(&self) -> f64 {
self.width * self.height
}
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
fn is_square(&self) -> bool {
self.width == self.height
}
}
struct Color(u8, u8, u8);
fn main() {
let rect = Rectangle::new(5.0, 3.0);
println!("Rectangle: {:?}", rect);
println!("Area: {}", rect.area());
println!("Perimeter: {}", rect.perimeter());
println!("Is square: {}", rect.is_square());
let square = Rectangle::new(4.0, 4.0);
println!("Is square: {}", square.is_square());
let red = Color(255, 0, 0);
println!("Red: ({}, {}, {})", red.0, red.1, red.2);
}
Which receiver type should you use for a method that only needs to read struct fields?
How do you call an associated function named new on a struct called Rectangle?
What distinguishes a tuple struct from a plain tuple?