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.
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.
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.
struct Unit;
Generics
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.
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
#[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))
}
}