What are Structs?
A struct (short for “structure”) in Rust is a custom data type that lets you name and group multiple related values of different types into a single entity. Structs are similar to objects in object-oriented programming but without methods.
Types of Structs in Rust
Rust supports three main types of structs:
- Named Field Structs: The most common type, where each field has a name and a type.
- Tuple Structs: Structs that look like tuples but have a custom type.
- Unit-like Structs: Structs without any fields, often used for marker or placeholder purposes.
Defining and Using Named Field Structs
Named field structs have explicitly named fields, making them highly readable.
Example:
struct Person {
name: String,
age: u32,
is_student: bool,
}
fn main() {
let person = Person {
name: String::from("Alice"),
age: 25,
is_student: true,
};
println!("Name: {}", person.name);
println!("Age: {}", person.age);
println!("Is Student: {}", person.is_student);
}
Output:
Name: Alice
Age: 25
Is Student: true
Defining and Using Tuple Structs
Tuple structs group fields without naming them but provide a custom type.
Example:
struct Color(u8, u8, u8);
fn main() {
let red = Color(255, 0, 0);
println!("Red Color: ({}, {}, {})", red.0, red.1, red.2);
}
Output:
Red Color: (255, 0, 0)
Defining and Using Unit-like Structs
Unit-like structs don’t have any fields. They are useful for defining unique types or implementing traits.
Example:
struct Marker;
fn main() {
let marker = Marker;
println!("Marker struct instantiated.");
}
Output:
Marker struct instantiated.
Struct Updates Using Struct Update Syntax
Rust allows you to create a new instance of a struct by copying fields from another instance using the . . syntax.
Example:
struct Person {
name: String,
age: u32,
is_student: bool,
}
fn main() {
let person1 = Person {
name: String::from("Bob"),
age: 30,
is_student: false,
};
let person2 = Person {
name: String::from("Alice"),
..person1
};
println!("Person2: {}, {}, {}", person2.name, person2.age, person2.is_student);
}
Output:
Person2: Alice, 30, false
Borrowing and Ownership with Structs
When using structs, you can borrow fields instead of taking ownership to avoid moving the values.
Example:
struct Person {
name: String,
age: u32,
}
fn print_name(person: &Person) {
println!("Name: {}", person.name);
}
fn main() {
let person = Person {
name: String::from("Charlie"),
age: 40,
};
print_name(&person);
println!("Age: {}", person.age);
}
Output:
Name: Charlie
Age: 40
Destructuring Structs
Rust allows destructuring structs to extract values from fields.
Example:
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 10, y: 20 };
let Point { x, y } = point;
println!("X: {}, Y: {}", x, y);
}
Output:
X: 10, Y: 20
Methods in Structs
You can define methods for structs using the impl block. These methods can act on struct fields and enhance the struct’s functionality.
Example:
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle {
width: 10,
height: 20,
};
println!("Area of Rectangle: {}", rect.area());
}
Output:
Area of Rectangle: 200
When to Use Structs
- To group related data together.
- To model entities in your application (e.g., a User, Product, or Order).
- To define custom data types with meaningful attributes.