讲解

方法(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。