news 2026/8/19 23:37:13

Rust教程-4.2 方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rust教程-4.2 方法

4.2 方法

方法(Method)是与结构体(或其他自定义类型)关联的函数。它们定义在impl块中,允许你为自定义类型赋予特定的行为,从而实现数据与行为的封装。Rust 中的方法分为两类:实例方法(与具体实例绑定)和关联函数(与类型本身绑定,最常见的就是new构造函数)。

4.2.1 在结构体上定义方法

要为一个结构体定义方法,需要使用impl(implementation)关键字。在impl块内定义的函数,其第一个参数必须是某种形式的self,这样它才能成为实例方法,并通过点号(.)语法在实例上调用。

示例:为 Rectangle 结构体定义方法

struct Rectangle { width: u32, height: u32, } impl Rectangle { // 定义一个实例方法 area fn area(&self) -> u32 { self.width * self.height } // 定义另一个实例方法 can_hold fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; let rect2 = Rectangle { width: 10, height: 40 }; // 通过点号语法调用方法 println!("rect1 的面积是: {} 平方像素", rect1.area()); println!("rect1 能容纳 rect2 吗? {}", rect1.can_hold(&rect2)); }

方法 vs 普通函数:

  • 调用方式不同:方法使用instance.method()的点号语法调用,而普通函数使用function()直接调用。
  • 自动引用:Rust 会根据方法的self参数类型,自动为实例添加引用(&)、可变引用(&mut)或直接取得所有权。你不需要在调用时手动写&rect1
  • 语义更清晰:方法明确表达了"这个行为属于这个类型",使代码更具可读性和组织性。

多个impl:Rust 允许为同一个类型定义多个impl块。这在大型项目中很有用,可以将不同功能的方法分组,或者将方法的定义和 trait 实现分开。

impl Rectangle { fn area(&self) -> u32 { self.width * self.height } } impl Rectangle { fn perimeter(&self) -> u32 { 2 * (self.width + self.height) } }
4.2.2 self 参数

方法的第一个参数决定了该方法如何"拥有"或"借用"调用它的实例。Rust 提供了三种self参数的形式,每种对应不同的所有权语义:

形式含义对实例的影响使用场景
&self不可变借用实例保持不变,可继续使用只读取数据,不修改
&mut self可变借用可以修改实例的字段需要修改实例的数据
self取得所有权实例被消耗,调用后原变量失效需要消耗或转换实例

示例:三种 self 参数的对比

#[derive(Debug)] struct Counter { value: i32, } impl Counter { // &self:不可变借用,只读取 fn display(&self) { println!("当前值: {}", self.value); } // &mut self:可变借用,可以修改 fn increment(&mut self) { self.value += 1; } // self:取得所有权,消耗实例 fn into_value(self) -> i32 { self.value } } fn main() { let mut counter = Counter { value: 0 }; counter.display(); // 使用 &self,counter 之后仍可使用 counter.increment(); // 使用 &mut self,counter 之后仍可使用 println!("{:?}", counter); // counter 仍然有效 let val = counter.into_value(); // 使用 self,counter 的所有权被转移 // counter.display(); // 编译错误!counter 已被消耗,不再有效 println!("最终值: {}", val); }

选择哪种 self 的指导原则:

  1. 优先使用&self:如果方法不需要修改实例,这是最安全、最灵活的选择。
  2. 需要修改时使用&mut self:当方法需要改变实例的状态时。
  3. 谨慎使用self:只在确实需要消耗实例时使用,例如将实例转换为另一种类型,或实现类似into_value这样的"消费并返回"模式。
4.2.3 关联函数

关联函数是定义在impl块中,但不以self作为参数的函数。它们不属于任何具体的实例,而是属于类型本身。最常见的关联函数是构造函数new,用于创建并返回类型的新实例。

关联函数通过双冒号::语法调用,而不是点号语法。

示例:定义和调用关联函数

struct Rectangle { width: u32, height: u32, } impl Rectangle { // 关联函数:没有 self 参数,通常用作构造函数 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 main() { // 通过 :: 语法调用关联函数 let rect = Rectangle::new(30, 50); let sq = Rectangle::square(10); // 通过 . 语法调用实例方法 println!("矩形面积: {}", rect.area()); println!("正方形面积: {}", sq.area()); }

关联函数的特点:

  • 无 self 参数:这是区分关联函数和实例方法的关键标志。
  • 命名空间:关联函数通常用于提供与类型相关的工具函数或工厂方法。
  • 常见命名约定
    • new()— 最常用的构造函数名。
    • from_xxx()— 从某种特定数据创建实例,如from_str()
    • default()— 创建具有默认值的实例。
    • with_xxx()— 创建实例并设置某些特定属性,如with_capacity()

一个类型可以有多个关联函数,它们为创建实例提供了不同的途径,使 API 更加灵活和直观。

impl Rectangle { fn new(width: u32, height: u32) -> Self { Self { width, height } } fn from_diameter(diameter: u32) -> Self { Self { width: diameter, height: diameter, } } fn unit_square() -> Self { Self::new(1, 1) } }

Self类型别名:在impl块中,Self是当前类型的别名。在上面的例子中,Self等价于Rectangle。使用Self可以让代码更简洁,也便于将来重构时减少修改量。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/19 23:37:03

深入解析CAN总线位周期:从时序原理到工程配置实战

1. 从“位”到“周期”:理解CAN通信的基石如果你接触过汽车电子或者工业控制,CAN总线这个词一定不陌生。它就像设备之间的“神经系统”,负责传递各种控制指令和状态信息。但很多人,包括一些刚开始接触的工程师,往往把重…

作者头像 李华
网站建设 2026/8/19 23:36:43

架构重构的艺术:如何让老系统重获新生

架构重构的艺术:如何让老系统重获新生 想象一下:你的煎饼摊用了10年的老炉子,火力不够了,外观也过时了。但直接换新炉子吧,顾客等着吃;不换吧,生意受影响。 架构重构就是这种两难处境的解决方案。 什么是架构重构 架构重构 = 在不影响业务的前提下,对系统架构进行调…

作者头像 李华
网站建设 2026/8/19 23:35:52

2026年7月滁州市新房价格深度分析报告

一、报告摘要本报告基于2026年7月滁州市新房实际成交案例,从成交价格、区域分布、户型结构、购房人群特征等维度进行深度分析。数据显示,2026年7月滁州市新房成交均价为每平方米7820元,环比上涨1.2%,同比上涨3.8%。其中&#xff0…

作者头像 李华
网站建设 2026/8/19 23:33:44

上位机通信究竟难在哪里,我花了八年才把这些坑捋明白

很多人问我,上位机开发最难的是啥。我说界面?不对,那玩意儿就是个壳子。数据库?也不对,SQL写熟了就那么几条。最难的是通信,就这一块,能卡死你大半的项目时间。 我刚入行的时候天真得很&#x…

作者头像 李华
网站建设 2026/8/19 23:28:40

ESP32触摸屏开发实战:用Visuino图形化编程快速构建交互界面

1. 项目概述:当ESP32遇上触摸屏与图形化编程如果你手头有一块M5Stack Core2 ESP32开发板,看着那块2英寸的电容触摸屏,心里琢磨着除了跑跑例程,还能用它做点什么有意思的东西,那么你来对地方了。这个项目就是关于如何释…

作者头像 李华
网站建设 2026/8/19 23:22:21

工业现场电磁干扰大,CRC错误频繁,软件层怎么做容错?

工业现场的电磁干扰是永远绕不开的话题:变频器启停、接触器吸合、大功率设备启停,都会在485总线、通信线缆上耦合出干扰脉冲,表现为偶发的CRC校验失败、数据错位、丢包。很多现场受限于布线、成本、生产节奏,无法彻底从硬件层面根治干扰,此时软件层的容错设计就成了系统稳…

作者头像 李华