结构体(struct)是 Rust 中自定义复合数据类型的主要方式,允许你将多个相关值组合在一起。
1. 基本结构体定义
定义和实例化
rust
// 定义结构体
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
// 创建实例
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
// 访问字段
println!("用户名: {}", user1.username);
println!("邮箱: {}", user1.email);
可变结构体
rust
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
// 修改字段值
user1.email = String::from("anotheremail@example.com");
user1.sign_in_count += 1;
2. 结构体更新语法
rust
let user1 = User {
email: String::from("user1@example.com"),
username: String::from("user1"),
active: true,
sign_in_count: 1,
};
// 使用更新语法创建新实例
let user2 = User {
email: String::from("user2@example.com"),
username: String::from("user2"),
..user1 // 继承 user1 的其他字段
};
// user2 将拥有 user1 的 active 和 sign_in_count 值
3. 元组结构体
没有字段名,只有类型的结构体:
rust
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
// 通过索引访问
println!("红色分量: {}", black.0);
println!("x坐标: {}", origin.0);
// 即使字段类型相同,也是不同的类型
// let color: Color = origin; // 错误!类型不匹配
4. 类单元结构体
没有字段的结构体:
rust
struct AlwaysEqual;
let subject = AlwaysEqual;
// 常用于 trait 实现或标记类型
impl AlwaysEqual {
fn new() -> Self {
AlwaysEqual
}
}
5. 结构体方法
定义方法
rust
struct Rectangle {
width: u32,
height: u32,
}
// 使用 impl 块定义方法
impl Rectangle {
// 关联函数(类似静态方法)
fn new(width: u32, height: u32) -> Self {
Rectangle { width, height }
}
// 实例方法
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
// 修改方法
fn scale(&mut self, factor: f32) {
self.width = (self.width as f32 * factor) as u32;
self.height = (self.height as f32 * factor) as u32;
}
// 获取器(getter)
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
}
// 使用
let rect = Rectangle::new(30, 50);
println!("面积: {}", rect.area());
let mut rect2 = Rectangle::new(10, 20);
rect2.scale(1.5);
多个 impl 块
rust
impl Rectangle {
fn square(size: u32) -> Self {
Rectangle { width: size, height: size }
}
}
impl Rectangle {
fn perimeter(&self) -> u32 {
2 * (self.width + self.height)
}
}
6. 关联函数 vs 方法
rust
struct Circle {
radius: f64,
}
impl Circle {
// 关联函数 - 没有 self 参数
fn new(radius: f64) -> Self {
Circle { radius }
}
// 方法 - 有 self 参数
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
// 使用
let circle = Circle::new(5.0); // 调用关联函数
let area = circle.area(); // 调用方法
7. 结构体与所有权
使用引用字段
rust
struct User<'a> {
username: &'a str, // 字符串切片引用
email: &'a str,
sign_in_count: u64,
}
let username = "john_doe";
let email = "john@example.com";
let user = User {
username,
email,
sign_in_count: 1,
};
使用 String(拥有所有权)
rust
struct OwnedUser {
username: String, // 拥有字符串所有权
email: String,
sign_in_count: u64,
}
8. Debug 打印
rust
#[derive(Debug)] // 自动实现 Debug trait
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 10, y: 20 };
println!("{:?}", point); // 调试输出: Point { x: 10, y: 20 }
println!("{:#?}", point); // 美化输出
// Point {
// x: 10,
// y: 20,
// }
9. 结构体模式匹配
rust
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 10, y: 20 };
// 解构结构体
let Point { x, y } = point;
println!("x: {}, y: {}", x, y);
// 模式匹配
match point {
Point { x: 0, y: 0 } => println!("原点"),
Point { x, y: 0 } => println!("x轴上的点: {}", x),
Point { x: 0, y } => println!("y轴上的点: {}", y),
Point { x, y } => println!("点({}, {})", x, y),
}
10. 常用 trait 派生
rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct Point {
x: i32,
y: i32,
}
#[derive(Debug, Default)]
struct Config {
timeout: u32,
retries: u32,
}
// 使用默认值
let config = Config::default(); // timeout: 0, retries: 0
11. 泛型结构体
rust
// 泛型结构体
struct Pair<T, U> {
first: T,
second: U,
}
// 使用
let integer_pair = Pair { first: 5, second: 10 };
let mixed_pair = Pair { first: "hello", second: 42.5 };
// 泛型方法实现
impl<T, U> Pair<T, U> {
fn new(first: T, second: U) -> Self {
Pair { first, second }
}
fn swap(self) -> Pair<U, T> {
Pair {
first: self.second,
second: self.first,
}
}
}
12. Newtype 模式
使用元组结构体创建新类型:
rust
struct Kilometers(i32);
struct Meters(i32);
let distance1 = Kilometers(5);
let distance2 = Meters(5000);
// 这样不会意外混淆不同类型
// let total = distance1 + distance2; // 编译错误!
13. 结构体最佳实践
- 命名规范:使用大驼峰命名法
- 字段访问:考虑提供 getter/setter
- 不可变性:优先使用不可变结构体
- 所有权:根据需求选择引用或拥有所有权
- 文档注释:为公共结构体添加文档
rust
/// 表示一个二维点
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Point {
/// x 坐标
pub x: f64,
/// y 坐标
pub y: f64,
}
impl Point {
/// 创建新点
pub fn new(x: f64, y: f64) -> Self {
Point { x, y }
}
/// 计算到原点的距离
pub fn distance_from_origin(&self) -> f64 {
(self.x * self.x + self.y * self.y).sqrt()
}
}
14. 结构体 vs 枚举 vs 元组
| 特性 | 结构体 | 枚举 | 元组 |
|---|---|---|---|
| 字段名 | 有 | 无 | 无 |
| 变体 | 无 | 有多个 | 无 |
| 访问 | 点号 | 模式匹配 | 索引 |
| 用途 | 数据聚合 | 选择分支 | 简单组合 |
总结
Rust 结构体提供了:
- 数据封装:将相关数据组合在一起
- 类型安全:编译时检查字段访问
- 方法封装:将数据与操作绑定
- 灵活性:支持泛型、生命周期等
- 模式匹配:强大的解构能力
结构体是 Rust 面向数据编程的核心,结合枚举和 trait,构成了 Rust 强大的类型系统。