[Rust] Struct
A struct is a custom data type that lets you package together and name multiple related values that make up a meaningful group.
Create Struct
We define a struct using the struct keyword.
And inside curly brackets, we define the names and types of fields.
struct Person {
name: String,
age: u8,
}
Instantiate Struct
We create an instance of that struct by specifying concrete values for each of the fields to use the struct.
let person1 = Person {
name: String::from("HoYa"),
age: 18,
};
We can use dot notation to access fields of structs.
If the instance is mutable, we can change a value.
let mut person1 = Person {
name: String::from("HoYa"),
age: 18,
};
person1.name = String::from("Kim");
If the parameter names and the struct field names are the same, we can use the field init shorthand syntax.
fn create_person(name: String, age: u8) -> Person {
Person { name, age }
}
let person1 = create_person(String::from("HoYa"), 18);
Using struct update syntax, we can create a new instance from an existing instance.
The .. operator must come last to specify that any remaining fields should get their values from the corresponding fields in a given instance.
let person2 = Person {
name: String::from("Park"),
..person1
};
Tuple Struct without Named Fields
To define a tuple struct, start with the struct keyword and the struct name followed by the types in the tuple.
struct Color(i32, i32, i32);
fn main() {
let black = Color(0, 0, 0);
}
Unit-LIke Struct without Any Fields
The unit-like struct doesn't have any fields.
It behaves similarly to ().
struct Nothing;
fn main() {
let test = Nothing;
}
Define Method
Methods are defined within impl block and their first parameter is always self.
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle {
width: 3,
height: 5,
};
println!("{}", rect1.area());
}
Method with Parameters
Methods can have more parameters after self.
They can be inside the same impl block or separated impl block.
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn is_big(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
// --- OR --- //
// impl Rectangle {
// fn area(&self) -> u32 {
// self.width * self.height
// }
// }
//
// impl Rectangle {
// fn is_big(&self, other: &Rectangle) -> bool {
// self.width > other.width && self.height > other.height
// }
// }
fn main() {
let rect1 = Rectangle {
width: 3,
height: 5,
};
let rect2 = Rectangle {
width: 1,
height: 2,
};
println!("{}", rect1.is_big(&rect2));
}
Associated Functions
All functions defined within an impl block are called associated functions because they're associated with the type named after the impl.
They don't have a self parameter.
Associated functions that aren't methods are often used for constructors that will return a new instance of the struct.
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
fn main() {
let rect1 = Rectangle::square(5);
println!("{}, {}", rect1.width, rect1.height);
}