Rust结构体方法语法:让数据拥有行为
Rust 支持中文定义结构体、方法、函数、变量。
结构体(struct)不仅是数据的容器,还能通过方法(method)定义专属行为。Rust通过impl
块将数据与操作紧密结合,配合derive(Debug)
实现便捷调试。本文通过实际案例,带你探索结构体方法的奥秘。
一、基础方法语法
示例1:定义简单方法
#[derive(Debug)] // 启用Debug trait
struct 玩家 {
名字: String,
等级: u32,
}
impl 玩家 {
// 实例方法:显示信息
fn 显示信息(&self) {
println!("玩家 {} (等级 {})", self.名字, self.等级);
}
// 关联函数:构造函数
fn 新建(名字: &str) -> Self {
玩家 {
名字: 名字.to_string(),
等级: 1,
}
}
}
fn main() {
let 新玩家 = 玩家::新建("张三");
新玩家.显示信息();
println!("调试信息: {:?}", 新玩家); // 使用Debug输出
}
输出:
玩家 张三 (等级 1)
调试信息: 玩家 { 名字: "张三", 等级: 1 }
二、可变方法
使用&mut self
参数可以修改结构体实例。
示例2:实现升级方法
#[derive(Debug)] // 启用Debug trait
struct 玩家 {
名字: String,
等级: u32,
}
impl 玩家 {
fn 升级(&mut self) {
self.等级 += 1;
println!("{} 升级到 {} 级!", self.名字, self.等级);
}
// 关联函数:构造函数
fn 新建(名字: &str) -> Self {
玩家 {
名字: 名字.to_string(),
等级: 1,
}
}
}
fn main() {
let mut 战士 = 玩家::新建("李四");
战士.升级();
战士.升级();
println!("当前状态: {:#?}", 战士); // 美化调试输出
}
输出:
李四 升级到 2 级!
李四 升级到 3 级!
当前状态: 玩家 {
名字: "李四",
等级: 3,
}
三、带参数的方法
方法可以接收额外参数实现更复杂逻辑。
示例3:战斗伤害计算
#[derive(Debug)] // 启用Debug trait
struct 玩家 {
名字: String,
等级: u32,
}
impl 玩家 {
fn 升级(&mut self) {
self.等级 += 1;
println!("{} 升级到 {} 级!", self.名字, self.等级);
}
// 关联函数:构造函数
fn 新建(名字: &str) -> Self {
玩家 {
名字: 名字.to_string(),
等级: 1,
}
}
}
#[derive(Debug)]
struct 战斗单位 {
名称: String,
生命值: i32,
攻击力: i32,
}
impl 战斗单位 {
fn 攻击(&self, 目标: &mut 战斗单位) {
let 伤害 = self.攻击力;
目标.生命值 -= 伤害;
println!(
"【{}】对【{}】造成 {} 点伤害",
self.名称, 目标.名称, 伤害
);
}
}
fn main() {
let mut 怪兽 = 战斗单位 {
名称: "火焰蜥蜴".to_string(),
生命值: 50,
攻击力: 8,
};
let 英雄 = 战斗单位 {
名称: "光明骑士".to_string(),
生命值: 100,
攻击力: 15,
};
英雄.攻击(&mut 怪兽);
println!("怪兽状态: {:?}", 怪兽);
}
输出:
【光明骑士】对【火焰蜥蜴】造成 15 点伤害
怪兽状态: 战斗单位 { 名称: "火焰蜥蜴", 生命值: 35, 攻击力: 8 }
四、链式方法调用
通过返回Self
实现链式调用。
示例4:流畅接口设计
#[derive(Debug)]
struct 坐标 {
x: i32,
y: i32,
}
impl 坐标 {
fn 新建(x: i32, y: i32) -> Self {
坐标 { x, y }
}
fn 移动_x轴(mut self, 距离: i32) -> Self {
self.x += 距离;
self
}
fn 移动_y轴(mut self, 距离: i32) -> Self {
self.y += 距离;
self
}
}
fn main() {
let 最终位置 = 坐标::新建(0, 0)
.移动_x轴(5)
.移动_y轴(3)
.移动_x轴(-2);
println!("最终坐标: {:?}", 最终位置);
}
输出:
最终坐标: 坐标 { x: 3, y: 3 }
五、多个impl块
Rust允许为同一结构体定义多个impl
块。
示例5:分块实现功能
#[derive(Debug)]
struct 温度计 {
温度: f32,
}
// 基础功能
impl 温度计 {
fn 当前温度(&self) -> f32 {
self.温度
}
}
// 扩展功能
impl 温度计 {
fn 设置温度(&mut self, 新温度: f32) {
self.温度 = 新温度;
println!("温度已更新");
}
}
fn main() {
let mut 测温仪 = 温度计 { 温度: 25.0 };
println!("初始温度: {:.1}℃", 测温仪.当前温度());
测温仪.设置温度(28.5);
println!("调试信息: {:#?}", 测温仪);
}
输出:
初始温度: 25.0℃
温度已更新
调试信息: 温度计 {
温度: 28.5,
}
综合示例:完整角色系统
#[derive(Debug)]
struct 游戏角色 {
名称: String,
职业: String,
生命值: u32,
魔法值: u32,
经验值: u32,
}
impl 游戏角色 {
// 关联函数:创建新角色
fn 创建(名字: &str, 职业: &str) -> Self {
游戏角色 {
名称: 名字.to_string(),
职业: 职业.to_string(),
生命值: 100,
魔法值: 50,
经验值: 0,
}
}
// 实例方法:显示状态
fn 状态报告(&self) {
println!(
"【{}】 {} 生命值:{} 魔法值:{} 经验值:{}",
self.职业, self.名称, self.生命值, self.魔法值, self.经验值
);
}
// 可变方法:获得经验
fn 获得经验(&mut self, 经验: u32) {
self.经验值 += 经验;
println!("{} 获得了 {} 点经验", self.名称, 经验);
}
// 链式方法:治疗角色
fn 治疗(mut self, 治疗量: u32) -> Self {
self.生命值 += 治疗量;
println!("治疗完成,当前生命值:{}", self.生命值);
self
}
}
fn main() {
// 创建角色
let mut 角色 = 游戏角色::创建("王五", "法师");
// 初始状态
println!("=== 初始状态 ===");
角色.状态报告();
println!("调试信息:{:?}\n", 角色);
// 获得经验
角色.获得经验(150);
// 治疗并链式调用
let 角色 = 角色.治疗(30);
// 最终状态
println!("\n=== 最终状态 ===");
角色.状态报告();
println!("美化调试信息:\n{:#?}", 角色);
}
输出:
=== 初始状态 ===
【法师】 王五 生命值:100 魔法值:50 经验值:0
调试信息:游戏角色 { 名称: "王五", 职业: "法师", 生命值: 100, 魔法值: 50, 经验值: 0 }
王五 获得了 150 点经验
治疗完成,当前生命值:130
=== 最终状态 ===
【法师】 王五 生命值:130 魔法值:50 经验值:150
美化调试信息:
游戏角色 {
名称: "王五",
职业: "法师",
生命值: 130,
魔法值: 50,
经验值: 150,
}
总结要点
-
方法分类
- 关联函数:
fn 新建() -> Self
(类似构造函数) - 实例方法:
fn 方法(&self)
(只读访问) - 可变方法:
fn 方法(&mut self)
(修改实例)
- 关联函数:
-
调试利器
通过#[derive(Debug)]
自动实现Debug trait,使用{:?}
快速打印结构体内容 -
设计模式
- 链式调用:返回
Self
实现流畅接口 - 分块实现:多个
impl
块提高代码可读性
- 链式调用:返回
-
安全保证
- 编译器自动检查可变性
- 所有权系统防止悬垂引用
掌握方法语法,让Rust结构体真正成为既有数据又有行为的完整对象!