Structs are like objects in Javascript, with named fields that can have different types
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("[email protected]"),
sign_in_count: 1,
};
}
Fields can be accessed using dot notation: user1.active
They can also be updated using dot notation so long as the instance (user1 above) is mutable
Much like Javascript, you can set fields shorthand if the names line up:
fn build_user(email: String, username: String) -> User {
User {
active: true,
username,
email,
sign_in_count: 1,
}
}
Rust also has a spread-like operator to copy many fields from one struct to another. However, note that the “spread” struct needs to come at the end, not the beginning:
fn main() {
// --snip--
let user2 = User {
email: String::from("[email protected]"),
..user1
};
}
Be careful when copying structs like this, anything that is copied over that uses the drop method will be moved rather than copied. For example a String. Because it is moved, the struct it is copied from becomes invalid. However, any fields within that struct that are copyable (e.g. integers) remain valid via dot-notation access.
Methods are added to structs by using impl :
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
Any function defined in an impl block is known as an associated function. Associated functions don’t have to have &self as the first argument, but are only methods if they do.
If they don’t then they are effectively static functions on the struct type, that can be accessed using Struct::fn :
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}
// Rectangle::square(12)