Skip to content

Structs

Basic Structs

Structs are similar to tuples in that they hold multiple values, however their properties are named. Struct fields are also mutable.

Note that you should always use String in structs because we want the data to live on the structs stack and die when the struct does. When possible, all data in the struct should belong to the struct, otherwise you will need to implement lifetimes.

rust
struct User {
    username: String,
    email: String,
    age: i32,
    active: bool
}

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    age: 29,
}; 

fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}

let user2 = User {
    email: String::from("another@example.com"),
    ..user1
};

Tuple Structs

Tuple stucts are structs that have unnamed fields and are only defined by the types. You would use this when you want the tuple to be a different type than other tuples, but naming the fields would be unnecessary.

rust
struct Color(i8,i8,i8);
let _black = Color(0, 0, 0);

Unit Like Struct

These types of structs are used when you only want to apply traits to a type that doesn't require any data.

rust
struct Unit;

Generics

rust
struct Point<T> {
    x: T,
    y: T
}

let _integer = Point { x: 5, y: 10 };
let _float = Point { x: 1.0, y: 4.0 };

Methods

Methods are defined by implementing a struct with the impl keyword. Here the functions can accept a reference to self to have access to all of the instance variables of that class. You can have multiple impl blocks if you want.

rust
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn new(w: i32, h: i32) -> Rectangle {
        Rectangle {
            width: w,
            height: h
        }
    }

    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size
        }
    }
}

Overloading Methods

rust
#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

struct Millimeters(u32);
struct Meters(u32);

// Using different types
impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}