rust 结构体(Struct)
结构体是 Rust 中自定义复合数据类型的基础工具。它将多个可能不同类型的值组合成一个有意义的整体,就像现实中的“表单”或“档案”。
1. 结构体是什么?有什么作用?
功能作用结构体允许你把相关的数据打包成一个新的类型。例如,描述一个“学生”需要姓名、年龄、学号等数据,结构体就能把这些字段捆绑在一起。这样做的好处是:
- 代码更清晰,数据关系一目了然。
- 可以针对这个结构体实现专属的行为(方法)。
- 类型安全,编译器能帮你检查字段使用是否正确。
2. 结构体的基本规则(抽象结构)
// 定义结构体
struct 结构体名称 {
字段名1: 类型1,
字段名2: 类型2,
...
}
// 创建结构体实例-赋值(不可变)
let 实例 = 结构体名称 {
字段名1: 值1,
字段名2: 值2,
...
};
// 创建可变实例(可以修改字段)
let mut 实例 = 结构体名称 { ... };
实例.字段名1 = 新值;
// 访问字段
实例.字段名
- 每个字段必须声明类型,字段之间用逗号分隔。
- 默认情况下实例是不可变的,要修改字段需要将实例声明为
mut。 - 可以使用 结构体更新语法(
..other_instance)从另一个实例复制剩余字段。
3. 结构体示例
3.1 定义与实例化
// 定义一个用户结构体
struct User {
username: String,
email: String,
active: bool,
sign_in_count: u64,
}
fn main() {
// 创建不可变实例
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
sign_in_count: 1,
};
println!("用户名: {}", user1.username);
// 创建可变实例,并修改 email
let mut user2 = User {
email: String::from("bob@example.com"),
username: String::from("bob"),
active: false,
sign_in_count: 0,
};
user2.email = String::from("bob_new@example.com");
println!("新邮箱: {}", user2.email);
}
3.2 使用字段初始化简写
当函数参数名与结构体字段名相同时,可以省略重复:
#![allow(unused)]
fn main() {
fn build_user(email: String, username: String) -> User {
User {
email, // 等价于 email: email
username, // 等价于 username: username
active: true,
sign_in_count: 1,
}
}
}
3.3 结构体更新语法
从已有实例快速创建新实例,只修改部分字段:
#![allow(unused)]
fn main() {
let user3 = User {
email: String::from("charlie@example.com"),
..user1 // 其余字段与 user1 相同(username、active、sign_in_count)
};
}
注意:更新语法会发生所有权的转移。如果原字段类型没有实现
Copytrait(如String),原实例将不再可用(这里user1的username被移动到了user3)。
4. 为结构体定义方法(impl 块)
方法类似于其他语言的成员函数,定义在 impl 块中。第一个参数通常是 &self(不可变引用)、&mut self(可变引用)或 self(获取所有权)。
4.1 方法的基本规则
impl 结构体名称 {
// 关联函数(没有 self 参数,通常用作构造器)
fn 函数名(参数列表) -> Self { ... }
// 实例方法(只读)
fn 方法名(&self, 其他参数) -> 返回类型 { ... }
// 实例方法(可修改)
fn 方法名(&mut self, 其他参数) { ... }
}
Self(大写 S)是当前结构体类型的别名。&self是self: &Self的缩写,表示对实例的不可变引用。- 调用方法时使用点语法:
实例.方法名()。
4.2 方法示例
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 关联函数:构造函数
fn new(width: u32, height: u32) -> Self {
Self { 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 double(&mut self) {
self.width *= 2;
self.height *= 2;
}
}
fn main() {
let rect = Rectangle::new(30, 50);
println!("面积: {}", rect.area());
let mut rect2 = Rectangle::new(10, 20);
rect2.double();
println!("double 后宽度: {}", rect2.width); // 20
}
5. 完整示例
下面的示例定义了一个 MyStruct 结构体,包含三个字段,并实现了关联函数 new 和实例方法 demo。最后在 demo 函数中演示了如何使用。
5.1 代码
#![allow(unused)]
fn main() {
// 定义一个结构体 MyStruct,包含 a、b、c 三个字段
// a、b 为整数类型,c 为字符串类型
struct MyStruct {
a: i32,
b: i32,
c: String,
}
// impl 关键字用于给结构体实现方法
impl MyStruct {
// 关联函数 new,用作构造函数
// Self 关键字代表当前结构体类型(即 MyStruct)
fn new() -> Self {
Self {
a: 0,
b: 0,
c: String::from("hello"),
}
}
// 实例方法 demo
// &self 表示当前结构体实例的不可变引用(类似于其他语言的 this)
fn demo(&self) {
let res = self.a + self.b;
println!("res: {} , c: {}", res, self.c);
}
}
pub fn demo() {
println!("...............结构体示例开始.................");
// 创建 MyStruct 实例,使用 :: 调用关联函数 new
let ms = MyStruct::new();
// 调用实例方法 demo
ms.demo();
println!("...............结构体示例结束.................");
}
}