讲解
方法(method)是定义在某个类型上的函数,写在 impl 块(implementation 块)里,第一个参数永远是 self 的某种形式。三种形式对应三种用法:&self 只读借用(最常见,方法只看不改);&mut self 可变借用(方法要改实例状态);self 拿走所有权(少见,用于「消费」实例的转换方法)。调用统一用点号:rect.area()——Rust 会根据方法签名自动处理引用和解引用,不需要手动写 (&rect).area()。
关联函数(associated function)是 impl 块里不以 self 为第一参数的函数,用类型名加双冒号调用:String::from、Rectangle::square。它相当于其他语言的「静态方法」,最典型的用途是构造函数——社区约定叫 new(注意 new 不是关键字,只是约定)。
一个类型可以有多个 impl 块,语法允许,风格上没必要就写一个。另外 impl 块不只属于结构体,枚举(第 14 章)同样能定义方法——Option 的 .map()、Result 的 .unwrap_or() 都是枚举上的方法。
示例
方法与关联函数的完整形态:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
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: u32) {
self.width *= factor;
self.height *= factor;
}
// 关联函数:没有 self,用 Rectangle::square(5) 调用
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
fn main() {
let mut rect = Rectangle {
width: 30,
height: 50,
};
assert_eq!(rect.area(), 1500);
let small = Rectangle::square(10);
assert!(rect.can_hold(&small));
assert!(!small.can_hold(&rect));
rect.scale(2);
assert_eq!(rect.area(), 6000);
println!("{:?} 面积 {}", rect, rect.area());
}
常见坑
- 第一个参数忘写 self:impl 块里 fn area() 就成了关联函数,rect.area() 会报「没找到方法」;要当方法就得有 self 参数。
- 该用 &self 写了 self:self 参数会移动并消耗实例,调用一次方法实例就没了——除非你明确想要「消费」语义,否则用 &self。
- 手动解引用调用:(&rect).area() 能编译但多余;Rust 的自动引用/解引用让 rect.area() 永远是对的写法。
- 一个类型拆一堆 impl 块:语法允许,但没有泛型/特征拆分等正当理由时,合并成一个块更好读。
小结
impl 块装方法;&self 读、&mut self 改、self 消费;关联函数(如 new、square)用 :: 调用。至此结构体有数据有行为。下一章看 Rust 里另一个主力类型:枚举与 match。