Skip to content

函数 方法

在 Rust 中,impl 和 fn 是用于定义函数的关键字,但它们有不同的作用和使用方式。

我个人觉得有点像给给一个对象(结构体)添加一个静态方法;其中 impl 可以拿到当前结构体中的参数,类似 class

举个栗子:

js 中长这样

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:

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 也可以定义多个),例如以下代码:

rust
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

先开个示例代码:

rust
#[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 访问器,例如:

rust
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,所以也不能用.的方式调用方法,只能用::,

为枚举实现方法

rust
#![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();
}