Structs
## Learning Objectives
- Define and instantiate structs
- Use method syntax with impl
- Create associated functions
- Understand tuple structs
- Master struct updating
## Defining Structs
### Classic Struct
```rust
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect = Rectangle {
width: 30,
height: 50,
};
println!("{} x {}", rect.width, rect.height);
}
```
### Tuple Struct
```rust
struct Point(i32, i32);
struct Color(u8, u8, u8);
fn main() {
let point = Point(10, 20);
let color = Color(255, 0, 0);
println!("{} {}", point.0, point.1);
println!("R {} G {} B {}", color.0, color.1, color.2);
}
```
### Unit-Like Struct
```rust
struct AlwaysEqual;
fn main() {
let _subject = AlwaysEqual;
}
```
## Instantiating Structs
### Create Instance
```rust
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice123"),
active: true,
sign_in_count: 1,
};
}
```
### Field Init Shorthand
```rust
fn build_user(email: String, username: String) -> User {
User {
email, // Same as email: email
username, // Same as username: username
active: true,
sign_in_count: 1,
}
}
```
## Mutating Struct Fields
```rust
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let mut rect = Rectangle {
width: 30,
height: 50,
};
rect.width = 40;
println!("{} x {}", rect.width, rect.height);
}
```
## Method Syntax
### impl Block
```rust
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("Area: {}", rect.area());
}
```
### Methods with Parameters
```rust
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
fn set_width(&mut self, width: u32) {
self.width = width;
}
}
```
### Associated Functions
Functions that don't take `self` as parameter:
```rust
impl Rectangle {
fn new(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
fn main() {
let rect = Rectangle::new(30, 50);
let sq = Rectangle::square(20);
}
```
### Multiple impl Blocks
```rust
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
```
## Struct Update Syntax
### Copy All Fields
```rust
struct Point {
x: i32,
y: i32,
z: i32,
}
fn main() {
let p1 = Point { x: 1, y: 2, z: 3 };
let p2 = Point {
x: 10,
..p1 // Copy remaining fields from p1
};
println!("{} {} {}", p2.x, p2.y, p2.z); // 10 2 3
}
```
### With Tuple Structs
```rust
struct Point(i32, i32, i32);
fn main() {
let p1 = Point(1, 2, 3);
let p2 = Point(10, ..p1);
println!("{} {} {}", p2.0, p2.1, p2.2); // 10 2 3
}
```
## Ownership in Structs
### Owned Values
```rust
struct User {
username: String,
email: String,
}
fn main() {
let user = User {
email: String::from("alice@example.com"),
username: String::from("alice123"),
};
// user.email and user.username own their data
}
```
### Reference Values
```rust
struct User {
username: &str, // Lifetimes needed!
email: &str,
}
// Better approach: use owned String
struct User {
username: String,
email: String,
}
```
## Example: Rectangle with Methods
```rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn new(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
}
fn main() {
let rect = Rectangle::new(30, 50);
let sq = Rectangle::square(20);
println!("{:?}", rect);
println!("Area: {}", rect.area());
println!("Can hold square? {}", rect.can_hold(&sq));
}
```
## Debug Trait
```rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("{:?}", rect); // Debug format
println!("{:#?}", rect); // Pretty debug
}
```
## Summary
- Structs group related data
- Tuple structs name tuple collections
- Unit-like structs for marker types
- Methods defined in `impl` blocks
- `&self` borrows the instance
- Associated functions don't take `self` (constructors)
- Struct update syntax `..` copies remaining fields
- Use `#[derive(Debug)]` for debug output
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →