👈 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 泛型和特征