LOADING

加载过慢请开启缓存 浏览器默认开启

方法 Method

2024/1/12 Rust

1. 定义方法

Rust 使用 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)
    }
}

Rust和其它语言,例如Java中的类不同的是,impl只能用来定义方法,里面不能包括属性,而Java中的类既可以有方法,也可以有属性。
如果需要使用属性,需要搭配结构体使用。

如果implstruct的名称相同,则两者会被视作同一个:

#[derive(Debug)]
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`` 的签名中,我们使用 &self替代rectangle: &Rectangle&self其实是self: &Self的简写(注意大小写)。在一个impl 块内,Self 指代被实现方法的结构体类型,self 指代此类型的实例,换句话说,self指代的是Rectangle结构体实例,这样的写法会让我们的代码简洁很多,而且非常便于理解:我们为哪个结构体实现方法,那么self` 就是指代哪个结构体的实例。

需要注意的是,self 依然有所有权的概念:

  • self 表示 Rectangle 的所有权转移到该方法中,这种形式用的较少
  • &self 表示该方法对 Rectangle 的不可变借用
  • &mut self 表示可变借用

2. 关联函数

参数中不包含 self 的函数就是关联函数,注意是函数而不是方法。

impl Rectangle {
    fn new(w: u32, h: u32) -> Rectangle {
        Rectangle { width: w, height: h }
    }
}

在Rust中,并没有构造器的概念,也就是说构造一个对象并不一定需要调用new方法,而new方法在语法层面也并不代表构造器,只是一个
约定俗成的规则,Rust里使用new作为构造器的名称。

因为是函数,所以不能用.来调用,只能通过::来调用,例如String::from

3. 多个impl定义

Rust 允许我们为一个结构体定义多个 impl 块,目的是提供更多的灵活性和代码组织性,例如当方法多了后,可以把相关的方法组织在同一个 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
    }
}

4. 为枚举实现方法

枚举类型之所以强大,不仅仅在于它好用、可以同一化类型,还在于,我们可以像结构体一样,为枚举实现方法:

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