Rust Structs: Defining Custom Data Types
Structs (short for "structures") are fundamental in Rust for creating custom data types. They allow you to group together related data into a single unit. Think of them as blueprints for creating objects with specific properties.
1. Defining a Struct
The struct keyword is used to define a struct. Here's the basic syntax:
struct StructName {
field1: Type1,
field2: Type2,
// ... more fields
}
StructName: The name of your struct. Conventionally, struct names are PascalCase (e.g.,Person,Rectangle).field1,field2, etc.: The names of the fields within the struct. Conventionally, field names are camelCase (e.g.,first_name,width).Type1,Type2, etc.: The data types of each field (e.g.,i32,String,bool).
Example:
struct Point {
x: i32,
y: i32,
}
struct Rectangle {
width: u32,
height: u32,
}
struct User {
username: String,
email: String,
active: bool,
}
2. Instantiating a Struct (Creating Instances)
Once you've defined a struct, you can create instances of it. This is done by providing values for each field.
let point1 = Point { x: 10, y: 20 };
let rect1 = Rectangle { width: 30, height: 50 };
let user1 = User {
username: String::from("Alice"),
email: String::from("alice@example.com"),
active: true,
};
3. Accessing Struct Fields
You access the fields of a struct using the dot (.) operator.
println!("Point x: {}", point1.x); // Output: Point x: 10
println!("Rectangle width: {}", rect1.width); // Output: Rectangle width: 30
println!("User username: {}", user1.username); // Output: User username: Alice
4. Tuple Structs
Rust also offers tuple structs. These are similar to regular structs, but their fields don't have names. They're useful when you want to create a simple data structure without needing to name each field.
struct Color(i32, i32, i32); // Red, Green, Blue
let red = Color(255, 0, 0);
println!("Red value: {}", red.0); // Output: Red value: 255
Notice how you access the fields using numerical indices (0, 1, 2, etc.).
5. Unit Structs
A unit struct is a struct that doesn't have any fields. They're primarily used as markers or to implement traits.
struct Marker;
let marker = Marker; // No fields to initialize
6. Associated Functions (Methods)
You can define functions associated with a struct using the impl block. These functions are often called methods.
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// Associated function (like a static method)
fn new(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
// Method (takes `self` as an argument)
fn area(&self) -> u32 {
self.width * self.height
}
fn is_square(&self) -> bool {
self.width == self.height
}
}
fn main() {
let rect = Rectangle::new(10, 20); // Call associated function
println!("Area: {}", rect.area()); // Call method
println!("Is square: {}", rect.is_square());
}
impl Rectangle: This block defines methods for theRectanglestruct.fn new(width: u32, height: u32) -> Rectangle: This is an associated function. It's called usingRectangle::new(...)and doesn't take aselfargument. It's often used as a constructor.fn area(&self) -> u32: This is a method. It takesselfas the first argument, which represents the instance of the struct. The&selfmeans it borrows the struct immutably. You can also use&mut selffor mutable access.
Key Takeaways:
- Structs are used to create custom data types.
- They group related data together.
- You access fields using the dot operator (
.). implblocks are used to define associated functions (methods) for structs.- Tuple structs are simple structs without named fields.
- Unit structs are structs without any fields.
Structs are a cornerstone of Rust programming, enabling you to model complex data structures and create well-organized, maintainable code. They are often used in conjunction with enums to represent a wide range of data scenarios.