方法
方法是从属于对象的函数(Mathods are functions attached to objects)。这些方法通过
关键字 self
来访问对象中的数据和其他方法。方法在 impl
代码块下定义。
struct Point { x: f64, y: f64, } // 实现的代码块,所有的 `Point` 方法都在这里给出 impl Point { // 这是一个静态方法(static method) // 静态方法不需要通过实例来调用 // 这类方法一般用作构造器(constructor) fn origin() -> Point { Point { x: 0.0, y: 0.0 } } // 另外一个静态方法,带有两个参数: fn new(x: f64, y: f64) -> Point { Point { x: x, y: y } } } struct Rectangle { p1: Point, p2: Point, } impl Rectangle { // 这是实例方法(instance method) // `&self` 是 `self: &Self` 的语法糖(sugar),其中 `Self` 是所调用对象 // 的类型。在这个例子中 `Self` = `Rectangle` fn area(&self) -> f64 { // `self` 通过点运算符来访问结构体字段 let Point { x: x1, y: y1 } = self.p1; let Point { x: x2, y: y2 } = self.p2; // `abs` 是一个 `f64` 类型的方法,返回调用者的绝对值 ((x1 - x2) * (y1 - y2)).abs() } fn perimeter(&self) -> f64 { let Point { x: x1, y: y1 } = self.p1; let Point { x: x2, y: y2 } = self.p2; 2.0 * ((x1 - x2).abs() + (y1 - y2).abs()) } // 这个方法要求调用者对象是可变的 // `&mut self` 为 `self: &mut Self` 的语法糖 fn translate(&mut self, x: f64, y: f64) { self.p1.x += x; self.p2.x += x; self.p1.y += y; self.p2.y += y; } } // `Pair` 含有的资源:两个堆分配的整型 struct Pair(Box<i32>, Box<i32>); impl Pair { // 这个方法“消费”调用者对象的资源 // `self` 为 `self: Self` 的语法糖 fn destroy(self) { // 解构 `self` let Pair(first, second) = self; println!("Destroying Pair({}, {})", first, second); // `first` 和 `second` 离开作用域后释放 } } fn main() { let rectangle = Rectangle { // 静态方法使用双重冒号来调用 p1: Point::origin(), p2: Point::new(3.0, 4.0), }; // 实例方法通过点运算符来调用 // 注意第一个参数 `&self` 是隐式传递的,比如: // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)` println!("Rectangle perimeter: {}", rectangle.perimeter()); println!("Rectangle area: {}", rectangle.area()); let mut square = Rectangle { p1: Point::origin(), p2: Point::new(1.0, 1.0), }; // 报错! `rectangle` 是不可变的,但这方法需要一个可变对象 //rectangle.translate(1.0, 0.0); // 试一试 ^ 将此行注释去掉 // 正常运行!可变对象可以调用可变方法 square.translate(1.0, 1.0); let pair = Pair(Box::new(1), Box::new(2)); pair.destroy(); // 报错!前面的 `destroy` 调用“消费了” `pair` //pair.destroy(); // 试一试 ^ 将此行注释去掉 }