👈 5 模式匹配

方法往往与对象成对出现:

object.method()

方法与函数的对比:读取一个文件写入缓冲区——

  • 函数写法:read(file, buffer)
  • 方法写法:file.read(buffer)

impl

关键字 impl:为结构体定义方法。

struct Circle {
    x: f64,
    y: f64,
    radius: f64,
}
 
impl Circle { // 表明块的内容与 Circle 有关
    fn new(x: f64, y: f64, radius: f64) -> Circle {
        Circle {
            x: x,
            y: y,
            radius: radius,
        }
    }
	
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

impl Circle { } 块内,有一个函数和一个方法:

  • new():关联函数(标志:第一个参数不是 self),用于初始化当前结构体的实例。new 不是 Rust 的关键字,而是约定俗成的构造器名称。
  • area():方法(标志:第一个参数为 self),参数 &self 表示借用当前的 Circle 实例。

Rust 和其他语言中“类”的对比:

Rust 的对象定义(数据)与方法定义(使用)是分离的,灵活度很高。

另一个示例:

struct Rectangle {
    width: u32,
    height: u32,
}
 
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
 
fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}

self&self&mut self

再看 area

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

签名中的 &self 其实是 self: &Self 的简写,这里用 &self 指代 rectangle: &Rectangle

impl 块内,Self 指代被实现方法的结构体类型,self 指代结构体实例。

self 依然有所有权的概念:

  • self 表示所有权转移到方法内,使用较少,往往用于把当前的对象转成另外一个对象时使用。
  • &self 表示方法对结构体实例的不可变借用,只能读取实例的数据。
  • &mut self 表示可变借用,可以修改结构的数据。

方法与字段同名

Rust 允许方法与结构体的字段同名:

struct Rectangle {
    width: u32,
    height: u32,
}
 
impl Rectangle {
    fn width(&self) -> bool { // 与字段 width 同名
        self.width > 0
    }
}
 
fn main() {
    let rect = Rectangle {
        width: 30,
        height: 50,
    };
	
    if rect.width() { // 调用方法 width()
        println!("The rectangle has a nonzero width, it is {}", rect.width); // 调用字段 width
    }
}

方法与字段同名往往用于实现 getter,将对应方法设为 pub,从而访问私有字段。

默认所有字段都是私有的,只对当前文件可见。

在 C / C++ 中,有两种运算符用于方法调用:. 直接在对象上调用方法;-> 在对象的指针上调用方法,需要先解引用。如果 p 是一个指针,p->method() 等价于 (*p).method()

Rust 没有 -> 运算符,而有自动引用和解引用的功能,方法调用是 Rust 少数几个表现出这种功能的地方。当使用 p.method() 时,Rust 自动为 p 添加 & / &mut / *,使 p 与方法签名匹配。

多个参数

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
    }
}

关联函数

定义在 impl 块中且没有 self 参数的函数称为关联函数,因为它不能以 p.method() 的形式调用,因此称为函数。

另一种观点:方法 method 是关联函数 associated functions 的子集,只要在 impl 块中的都为关联函数,其中有 self 参数的为方法。

函数需要以 :: 调用:

struct Rectangle {
    width: u32,
    height: u32,
}
 
impl Rectangle {
    fn new(w: u32, h: u32) -> Rectangle {
        Rectangle {
            width: w,
            height: h,
        }
    }
}
 
fn main() {
    let sq = Rectangle::new(3, 3);
}

常用的 String::from 就是 String 的关联函数。

多个 impl

可以为一个结构体定义多个 impl 块,它们仍将共同实现该结构体的方法。好处是提高代码的可读性、灵活性。

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
 
impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

enum 实现方法

可以像为结构体实现方法一样,为枚举实现方法:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
}
 
impl Message {
    fn call(&self) {
        // ...
    }
}

👉 7 泛型和特征