第9篇:成员功能——为结构体添加能力 Rust中文编程

第9篇:成员功能------为结构体添加能力

作者: 李金雨
联系方式: wbtm2718@qq.com
目标读者: Rust中文编程
核心理念: AI时代必须使用中文编程,母语编程阅读效率极高


1. 开篇引入

本课目标

  • 理解什么是成员功能(方法)
  • 掌握为结构体实现方法的方法
  • 理解方法中的self参数
  • 理解关联函数的概念
  • 理解方法与函数的区别

生活场景引入

想象一下,你有一个机器人,它有各种功能:

  • 走路
  • 说话
  • 唱歌
  • 跳舞

这些功能是机器人的一部分,只能由机器人来执行。在编程中,方法就像机器人的功能,它是结构体的一部分,只能由结构体的实例来调用。

预期成果展示

通过这节课的学习,你将能够:

  • 为结构体实现方法
  • 调用结构体的方法
  • 理解方法中的self参数
  • 定义和使用关联函数
  • 区分方法与函数

2. 概念讲解

什么是成员功能(方法)

方法是与结构体关联的函数,它可以访问和修改结构体的字段。方法就像结构体的行为,是结构体的一部分。

为结构体实现方法

在Rust中,我们使用impl块来为结构体实现方法:

rust 复制代码
fn main() {
    impl 结构体名 {
        fn 方法名(&self, 参数: 类型) -> 返回类型 {
            // 方法体
        }
    }
}

例如,为学生结构体实现方法:

rust 复制代码
fn main() {
    struct 学生 {
        姓名: String,
        年龄: i32,
        成绩: i32,
        科目列表: Vec<String>,
    }

    impl 学生 {
        // 显示信息方法
        fn 显示信息(&self) {
            println!("姓名:{}", self.姓名);
            println!("年龄:{}岁", self.年龄);
            println!("成绩:{}分", self.成绩);
            println!("学习的科目:{:?}", self.科目列表);
        }

        // 学习方法
        fn 学习(&mut self, 科目: &str) {
            self.科目列表.push(String::from(科目));
            println!("{}正在学习{}", self.姓名, 科目);
        }

        // 考试方法
        fn 考试(&mut self, 分数: i32) {
            self.成绩 = 分数;
            println!("{}考了{}分", self.姓名, 分数);
        }
    }
}

self参数

方法的第一个参数通常是self,它代表调用方法的实例。self有三种形式:

  1. &self:不可变引用,用于只读操作
  2. &mut self:可变引用,用于修改操作
  3. self:值传递,会转移所有权
rust 复制代码
fn main() {
    struct 学生 {
        姓名: String,
        年龄: i32,
        成绩: i32,
        科目列表: Vec<String>,
    }

    impl 学生 {
        // 不可变方法(只读)
        fn 显示信息(&self) {
            // 只能读取字段,不能修改
        }

        // 可变方法(可修改)
        fn 学习(&mut self, 科目: &str) {
            // 可以修改字段
        }

        // 消费方法(转移所有权)
        fn 转换为字符串(self) -> String {
            format!("{},{}岁,{}分", self.姓名, self.年龄, self.成绩)
        }
    }
}

方法的调用

调用方法使用点号(.):

rust 复制代码
fn main() {
    struct 学生 {
        姓名: String,
        年龄: i32,
        成绩: i32,
        科目列表: Vec<String>,
    }

    impl 学生 {
        fn 显示信息(&self) {
            println!("姓名:{},年龄:{}岁,成绩:{}分", self.姓名, self.年龄, self.成绩);
        }

        fn 学习(&mut self, 科目: &str) {
            self.科目列表.push(String::from(科目));
        }

        fn 考试(&mut self, 分数: i32) {
            self.成绩 = 分数;
        }
    }

    let mut 学生一 = 学生 {
        姓名: String::from("张三"),
        年龄: 15,
        成绩: 0,
        科目列表: vec![],
    };

    // 调用显示信息方法
    学生一.显示信息();

    // 调用学习方法
    学生一.学习("数学");

    // 调用考试方法
    学生一.考试(95);

    // 再次显示信息
    学生一.显示信息();
}

关联函数

关联函数是与结构体关联的函数,但它不接收self参数。关联函数通常用于创建结构体实例,就像构造函数一样。

rust 复制代码
fn main() {
    struct 学生 {
        姓名: String,
        年龄: i32,
        成绩: i32,
        科目列表: Vec<String>,
    }

    impl 学生 {
        // 关联函数(构造函数)
        fn 新(姓名: String, 年龄: i32) -> Self {
            Self {
                姓名,
                年龄,
                成绩: 0,
                科目列表: vec![],
            }
        }
    }
}

调用关联函数使用::操作符:

rust 复制代码
fn main() {
    struct 学生 {
        姓名: String,
        年龄: i32,
        成绩: i32,
        科目列表: Vec<String>,
    }

    impl 学生 {
        fn 新(姓名: String, 年龄: i32) -> Self {
            Self {
                姓名,
                年龄,
                成绩: 0,
                科目列表: vec![],
            }
        }
    }

    let 学生一 = 学生::新(String::from("张三"), 15);
}

方法与函数的区别

区别 函数 方法
定义位置 任何地方 impl块内
调用方式 直接调用 通过实例调用
self参数 有(通常)
访问权限 只能通过参数访问数据 可以直接访问实例的字段

3. 动手实践

基础练习(必做)

  1. 为"动物"结构体添加"叫"的方法

    rust 复制代码
    struct 动物 {
        名称: String,
        年龄: i32,
        声音: String,
    }
    
    impl 动物 {
        // 关联函数(构造函数)
        fn 新(名称: String, 年龄: i32, 声音: String) -> Self {
            Self {
                名称,
                年龄,
                声音,
            }
        }
        
        // 叫的方法
        fn 叫(&self) {
            println!("{}在{}", self.名称, self.声音);
        }
        
        // 显示信息方法
        fn 显示信息(&self) {
            println!("名称:{}", self.名称);
            println!("年龄:{}岁", self.年龄);
            println!("声音:{}", self.声音);
        }
    }
    
    fn main() {
        let 猫 = 动物::新(String::from("猫咪"), 2, String::from("喵喵"));
        let 狗 = 动物::新(String::from("狗狗"), 3, String::from("汪汪"));
        
        猫.显示信息();
        猫.叫();
        
        狗.显示信息();
        狗.叫();
    }
  2. 为"汽车"结构体添加"加速"、"减速"方法

    rust 复制代码
    struct 汽车 {
        品牌: String,
        颜色: String,
        速度: f64,
    }
    
    impl 汽车 {
        // 关联函数(构造函数)
        fn 新(品牌: String, 颜色: String) -> Self {
            Self {
                品牌,
                颜色,
                速度: 0.0,
            }
        }
        
        // 加速方法
        fn 加速(&mut self, 增量: f64) {
            self.速度 += 增量;
            println!("{}加速了{}km/h,当前速度:{}km/h", self.品牌, 增量, self.速度);
        }
        
        // 减速方法
        fn 减速(&mut self, 减量: f64) {
            if self.速度 >= 减量 {
                self.速度 -= 减量;
                println!("{}减速了{}km/h,当前速度:{}km/h", self.品牌, 减量, self.速度);
            } else {
                self.速度 = 0.0;
                println!("{}减速到0km/h", self.品牌);
            }
        }
        
        // 显示信息方法
        fn 显示信息(&self) {
            println!("品牌:{}", self.品牌);
            println!("颜色:{}", self.颜色);
            println!("当前速度:{}km/h", self.速度);
        }
    }
    
    fn main() {
        let mut 我的汽车 = 汽车::新(String::from("大众"), String::from("黑色"));
        我的汽车.显示信息();
        
        我的汽车.加速(30.0);
        我的汽车.加速(20.0);
        我的汽车.减速(10.0);
        我的汽车.减速(50.0);
    }
  3. 为"书籍"结构体添加"显示信息"方法

    rust 复制代码
    struct 书籍 {
        书名: String,
        作者: String,
        价格: f64,
        页数: i32,
    }
    
    impl 书籍 {
        // 关联函数(构造函数)
        fn 新(书名: String, 作者: String, 价格: f64, 页数: i32) -> Self {
            Self {
                书名,
                作者,
                价格,
                页数,
            }
        }
        
        // 显示信息方法
        fn 显示信息(&self) {
            println!("书名:{}", self.书名);
            println!("作者:{}", self.作者);
            println!("价格:{}元", self.价格);
            println!("页数:{}页", self.页数);
        }
        
        // 计算每页数价格的方法
        fn 每页数价格(&self) -> f64 {
            self.价格 / self.页数 as f64
        }
    }
    
    fn main() {
        let 书籍一 = 书籍::新(
            String::from("Rust编程入门"),
            String::from("李金雨"),
            49.9,
            300
        );
        
        书籍一.显示信息();
        println!("每页数价格:{:.4}元", 书籍一.每页数价格());
    }

进阶练习(选做)

  1. 为"点"结构体添加方法

    rust 复制代码
    struct 点 {
        x: f64,
        y: f64,
    }
    
    impl 点 {
        // 关联函数(构造函数)
        fn 新(x: f64, y: f64) -> Self {
            Self { x, y }
        }
        
        // 计算到原点的距离
        fn 到原点距离(&self) -> f64 {
            (self.x * self.x + self.y * self.y).sqrt()
        }
        
        // 计算到另一个点的距离
        fn 到点距离(&self, 另一个点: &点) -> f64 {
            let 差x = 另一个点.x - self.x;
            let 差y = 另一个点.y - self.y;
            (差x * 差x + 差y * 差y).sqrt()
        }
        
        // 移动点
        fn 移动(&mut self, dx: f64, dy: f64) {
            self.x += dx;
            self.y += dy;
        }
    }
    
    fn main() {
        let mut 点一 = 点::新(0.0, 0.0);
        let 点二 = 点::新(3.0, 4.0);
        
        println!("点一:({}, {})", 点一.x, 点一.y);
        println!("点二:({}, {})", 点二.x, 点二.y);
        println!("点一到原点的距离:{}", 点一.到原点距离());
        println!("点一到点二的距离:{}", 点一.到点距离(&点二));
        
        点一.移动(1.0, 2.0);
        println!("移动后点一:({}, {})", 点一.x, 点一.y);
        println!("移动后点一到点二的距离:{}", 点一.到点距离(&点二));
    }
  2. 为"矩形"结构体添加方法

    rust 复制代码
    struct 矩形 {
        长: f64,
        宽: f64,
    }
    
    impl 矩形 {
        // 关联函数(构造函数)
        fn 新(长: f64, 宽: f64) -> Self {
            Self { 长, 宽 }
        }
        
        // 计算面积
        fn 面积(&self) -> f64 {
            self.长 * self.宽
        }
        
        // 计算周长
        fn 周长(&self) -> f64 {
            2.0 * (self.长 + self.宽)
        }
        
        // 判断是否为正方形
        fn 是正方形(&self) -> bool {
            self.长 == self.宽
        }
    }
    
    fn main() {
        let 矩形一 = 矩形::新(5.0, 3.0);
        let 矩形二 = 矩形::新(4.0, 4.0);
        
        println!("矩形一:长{},宽{}", 矩形一.长, 矩形一.宽);
        println!("面积:{}", 矩形一.面积());
        println!("周长:{}", 矩形一.周长());
        println!("是否为正方形:{}", 矩形一.是正方形());
        
        println!("\n矩形二:长{},宽{}", 矩形二.长, 矩形二.宽);
        println!("面积:{}", 矩形二.面积());
        println!("周长:{}", 矩形二.周长());
        println!("是否为正方形:{}", 矩形二.是正方形());
    }

挑战练习(拓展)

  1. 为"学生管理系统"添加方法

    rust 复制代码
    struct 学生 {
        姓名: String,
        年龄: i32,
        成绩: i32,
    }
    
    impl 学生 {
        // 关联函数(构造函数)
        fn 新(姓名: String, 年龄: i32, 成绩: i32) -> Self {
            Self {
                姓名,
                年龄,
                成绩,
            }
        }
        
        // 显示信息方法
        fn 显示信息(&self) {
            println!("姓名:{},年龄:{}岁,成绩:{}分", 
                     self.姓名, self.年龄, self.成绩);
        }
        
        // 修改成绩方法
        fn 修改成绩(&mut self, 新成绩: i32) {
            self.成绩 = 新成绩;
            println!("{}的成绩已修改为{}分", self.姓名, self.成绩);
        }
    }
    
    struct 学生管理系统 {
        学生们: Vec<学生>,
    }
    
    impl 学生管理系统 {
        // 关联函数(构造函数)
        fn 新() -> Self {
            Self {
                学生们: vec![],
            }
        }
        
        // 添加学生方法
        fn 添加学生(&mut self, 学生: 学生) {
            self.学生们.push(学生);
            println!("学生添加成功");
        }
        
        // 显示所有学生信息方法
        fn 显示所有学生(&self) {
            println!("学生列表:");
            for (索引, 学生) in self.学生们.iter().enumerate() {
                print!("第{}名:", 索引 + 1);
                学生.显示信息();
            }
        }
        
        // 计算平均成绩方法
        fn 计算平均成绩(&self) -> f64 {
            if self.学生们.is_empty() {
                return 0.0;
            }
            
            let mut 总分 = 0;
            for 学生 in &self.学生们 {
                总分 += 学生.成绩;
            }
            
            总分 as f64 / self.学生们.len() as f64
        }
    }
    
    fn main() {
        let mut 系统 = 学生管理系统::新();
        
        // 添加学生
        系统.添加学生(学生::新(String::from("张三"), 15, 95));
        系统.添加学生(学生::新(String::from("李四"), 14, 88));
        系统.添加学生(学生::新(String::from("王五"), 15, 92));
        
        // 显示所有学生
        系统.显示所有学生();
        
        // 计算平均成绩
        println!("平均成绩:{}分", 系统.计算平均成绩());
        
        // 修改学生成绩
        if let Some(学生) = 系统.学生们.get_mut(0) {
            学生.修改成绩(98);
        }
        
        // 再次显示所有学生
        系统.显示所有学生();
        // 再次计算平均成绩
        println!("平均成绩:{}分", 系统.计算平均成绩());
    }

4. 知识总结

核心概念回顾

  • 方法:与结构体关联的函数,通过实例调用
  • impl块:用于为结构体实现方法
  • self参数:方法的第一个参数,代表调用方法的实例
  • &self:不可变引用,用于只读操作
  • &mut self:可变引用,用于修改操作
  • 关联函数:与结构体关联但不接收self参数的函数
  • 构造函数:通常是关联函数,用于创建结构体实例

关键代码速查

功能 代码 说明
方法定义 fn 方法名(&self, 参数: 类型) -> 返回类型 { 代码 } 定义一个方法
可变方法 fn 方法名(&mut self, 参数: 类型) -> 返回类型 { 代码 } 定义一个可以修改实例的方法
关联函数 fn 函数名(参数: 类型) -> Self { 代码 } 定义一个关联函数
方法调用 实例.方法名(参数) 调用实例的方法
关联函数调用 结构体名::函数名(参数) 调用关联函数

常见错误提醒

  1. self参数:方法的第一个参数通常是self
  2. 引用类型:根据需要选择&self、&mut self或self
  3. 方法调用:方法需要通过实例调用,而不是直接调用
  4. 关联函数调用:关联函数需要通过结构体名调用

5. 课后作业

巩固练习题

  1. 编写一个程序,为"手机"结构体添加"打电话"、"发短信"方法
  2. 编写一个程序,为"学校"结构体添加"添加学生"、"显示学生"方法
  3. 编写一个程序,为"电影"结构体添加"播放"、"暂停"方法

创意编程题

  1. 发挥你的创意,创建一个程序,为"游戏角色"结构体添加"攻击"、"防御"、"移动"方法
  2. 编写一个程序,为"银行账户"结构体添加"存款"、"取款"、"查询余额"方法

下篇预习提示

下一篇我们将学习"归属权与借用------Rust的安全保障",这是Rust的特色功能,能够保证内存安全。预习一下:

  • 什么是归属权(所有权)?
  • 为什么Rust需要归属权?
  • 什么是借用?
  • 借用有什么规则?

恭喜你完成了第九篇教程!你已经掌握了为结构体添加方法的技巧,学会了如何让结构体具有更多的功能。继续加油,下一篇我们将学习Rust的特色功能------所有权和借用!

学习交流

如果你在学习过程中遇到任何问题,欢迎联系我:

  • ** 视频号,"时空系"
  • 邮箱: wbtm2718@qq.com
  • 其他提示:
  • 本人正在开发纯中文编程语言和编译器,有兴趣的可以交流
  • 本人正在写一本基于中国母语思维习惯的数学教材,可以让你一年内学完从初中到研究生的数学,而且可以让你快速掌握人工智能的关键数学知识,有兴趣的可以交流

祝你学习愉快!

相关推荐
Scott9999HH39 分钟前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海2 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨3 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
andxe3 小时前
安科士 AndXe 技术博客:400G QSFP112 SR4 光模块|AI 算力与超算短距互联最优方案
网络·人工智能·光模块·光通信
shiyi.十一4 小时前
第2章:应用层 — 知识要点与架构
网络·计算机网络·架构
doiito5 小时前
【AI 应用】从“外国人味”到地道中文:kokoroi-rs v0.1.2 架构升级深度解析
ai·rust·系统设计
DFT计算杂谈5 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
水境传感 李兆栋5 小时前
GNSS 位移监测站 :毫米级感知,筑牢安全监测防线
网络