写点什么

5 分钟速读之 Rust 权威指南(八)

用户头像
码生笔谈
关注
发布于: 2021 年 05 月 24 日
5分钟速读之Rust权威指南(八)

方法

方法与函数十分相似,它们都使用 fn 关键字及一个名称来进行声明,但是方法与函数依然是两个不同的概念,方法只能被定义在某个结构体、枚举类型、trait 对象的上下文中(后面会介绍枚举和 trait 对象),并且它们的第一个参数永远都是 self,用于指代调用该方法的结构体实例(可以理解为 JS 中的 this)。由于我们只接触过了结构体,所以本节只介绍结构体中的方法。

定义方法

定义一个结构体 Rect:


struct Rect {  width: u32,  height: u32,}
复制代码


为结构体实现一个计算面积的方法 area,使用 impl 关键字后面跟结构体名称来作为实现方法的区域,impl 意为实现(implementation):


impl Rect {  // 用定义函数的方式定义一个方法  // 第一个参数作为对调用方法的结构体的引用  // self这种声明方式跟TS中this的类型声明很像  fn area(&self) -> u32 {    self.width * self.height  }}
复制代码


使用方法:


let rect = Rect {  width: 100,  height: 100,};
// 调用area方法,此时方法中的第一个参数&self表示&rectprintln!("area:{}", rect.area());// area:10000
复制代码


当使用 object.something()调用方法时,Rust 会自动为调用者 object 添加 &、&mut 或*,以使其能够符合方法的签名。换句话说,下面两种方法调用是等价的:


rect.area();&rect.area();
复制代码


所以 rect 前边是否有 &或者 mut,是根据 area 方法第一个参数定义的时候对于 self 的定义推导出来的,例如自动将 rect 推断添加 mut:


impl Rect {  // 将第一个参数改为可变引用  fn area(&mut self) -> u32 {    self.height *= 2;    self.width * self.height  }}
// 标识rect为可修改let mut rect = Rect { width: 100, height: 100,};
// 此时这两个是等价的,rust将自动将rect推断成&mut rectprintln!("area:{}", rect.area()); // area:20000println!("area:{}", &mut rect.area()); // area:20000
复制代码


方法也允许附带其他参数,例如下面比较矩形大小的方法:


impl Rect {  // 声明第二个参数为另一个引用类型的Rect  fn can_hold(&self, other: &Rect) -> bool {    self.width > other.width && self.height > other.height  }}
// 定义三个rectlet rect1 = Rect { width: 50, height: 50 };let rect2 = Rect { width: 10, height: 10 };let rect3 = Rect { width: 60, height: 60 };
// 通过传参,比较rect1与其他两个的大小println!("{}", rect1.can_hold(&rect2)); // trueprintln!("{}", rect1.can_hold(&rect3)); // false
复制代码

关联函数

在定义方法的时候,如果这个方法没有 self 参数,这样方法称之为关联函数,使用双冒号调用,例如我们用过的 String::from 方法:


String::from("hello");
复制代码


为 Rect 定义一个关联函数,用于创建一个正方形:


impl Rect {  // 这里不用再定义self参数  fn square(size: u32) -> Rect {    Rect { width: size, height: size }  }}
// 创建一个10 * 10的矩形println!("{:?}", Rect::square(10));// Rect { width: 10, height: 10 }
复制代码

多个 impl 块

当一个结构体的方法很多的时候,我们就需要将方法拆分到多个 impl 块中进行维护:


struct Rect {  width: u32,  height: u32,}
impl Rect { area(&self) -> u32 { /* ... */ }}
impl Rect { can_hold(&self, other: &Rect) -> bool { /* ... */ }}
impl Rect { square(size: u32) -> Rect { /* ... */ }}
// 存在相同的方法名称报错:impl Rect { square() { /* ... */ } // 报错,重复的square方法定义}
复制代码


发布于: 2021 年 05 月 24 日阅读数: 7
用户头像

码生笔谈

关注

欢迎关注「码生笔谈」公众号 2018.09.09 加入

前端、Rust干货分享,一起成为更好的Javascripter & Rustacean

评论

发布
暂无评论
5分钟速读之Rust权威指南(八)