函数 方法
在 Rust 中,impl 和 fn 是用于定义函数的关键字,但它们有不同的作用和使用方式。
我个人觉得有点像给给一个对象(结构体)添加一个静态方法;其中 impl 可以拿到当前结构体中的参数,类似 class
举个栗子:
js 中长这样
// 定义一个包含静态方法的对象字面量
const MathUtils = {
square: function (x) {
return x * x;
},
cube: function (x) {
return x * x * x;
},
};
// 调用静态方法
const squareResult = MathUtils.square(3);
console.log("Square:", squareResult);
const cubeResult = MathUtils.cube(3);
console.log("Cube:", cubeResult);
如果用 rust:
// 定义一个结构体
struct MathUtils;
// 为结构体实现方法
impl MathUtils {
fn square(x: i32) -> i32 {
x * x
}
fn cube(x: i32) -> i32 {
x * x * x
}
}
// 调用静态方法
let square_result = MathUtils::square(3);
println!("Square: {}", square_result);
let cube_result = MathUtils::cube(3);
println!("Cube: {}", cube_result);
正文开始
Rust 使用 impl 来定义方法(impl 也可以定义多个),例如以下代码:
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
// new是Circle的关联函数,因为它的第一个参数不是self,且new并不是关键字
// 这种方法往往用于初始化当前结构体的实例
fn new(x: f64, y: f64, radius: f64) -> Circle {
Circle {
x: x,
y: y,
radius: radius,
}
}
// Circle的方法,&self表示借用当前的Circle结构体
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
self、&self 和 &mut self
先开个示例代码:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
// 这里的&self 代表了 Rectangle
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
在 area 的签名中,我们使用 &self
替代 rectangle: &Rectangle
,&self
其实是 self: &Self
的简写(注意大小写)。 在一个 impl 块内,Self
指代被实现方法的结构体类型,self
指代此类型的实例,换句话说,self
指代的是 Rectangle
结构体实例,这样的写法会让我们的代码简洁很多,而且非常便于理解:我们为哪个结构体实现方法,那么 self
就是指代哪个结构体的实例。
self 依然有所有权的概念:
- self 表示 Rectangle 的所有权转移到该方法中,这种形式用的较少
- &self 表示该方法对 Rectangle 的不可变借用
- &mut self 表示可变借用
self 的使用就跟函数参数一样,要严格遵守 Rust 的所有权规则。
简单总结下,使用方法代替函数有以下好处:
- 不用在函数签名中重复书写 self 对应的类型
- 代码的组织性和内聚性更强,对于代码维护和阅读来说,好处巨大
在 Rust 中,允许方法名跟结构体的字段名相同;
一般来说,方法跟字段同名,往往适用于实现 getter 访问器,例如:
pub struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
pub fn new(width: u32, height: u32) -> Self {
Rectangle { width, height }
}
pub fn width(&self) -> u32 {
return self.width;
}
}
fn main() {
let rect1 = Rectangle::new(30, 50);
println!("{}", rect1.width());
}
用这种方式,我们可以把 Rectangle 的字段设置为私有属性,只需把它的 new 和 width 方法设置为公开可见,那么用户就可以创建一个矩形,同时通过访问器 rect1.width() 方法来获取矩形的宽度,因为 width 字段是私有的,当用户访问 rect1.width 字段时,就会报错。注意在此例中,Self 指代的就是被实现方法的结构体 Rectangle。
关联函数
简单说就是在 impl 中,没有 self 的函数叫关联函数,因为没有 self,所以也不能用.
的方式调用方法,只能用::
,
为枚举实现方法
#![allow(unused)]
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// 在这里定义方法体
}
}
fn main() {
let m = Message::Write(String::from("hello"));
m.call();
}