方法语法

方法类似于函数:我们用 fn 关键字和一个名称来声明它们,它们可以有参数和返回值,并且包含一些在从其他地方调用该方法时运行的代码。与函数不同,方法是在结构体(或枚举、trait 对象,分别在第6章和第18章介绍)上下文中定义的,其第一个参数总是 self,代表调用该方法的结构体实例。

定义方法

让我们将接收 Rectangle 实例作为参数的 area 函数改为定义在 Rectangle 结构体上的 area 方法,如清单5-13所示。

文件名: src/main.rs

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

清单5-13:在Rectangle结构体上定义area方法
为了在Rectangle上下文中定义函数,我们开始了一个针对Rectangle的 impl(实现)块。这个 impl 块中的所有内容都与类型 Rectangle 相关联。然后我们把 area 函数移到 impl 的大括号内,并将签名中的第一个(也是唯一一个)参数改为 self,同时函数体内也相应替换。在 main 中,我们原本调用传入 rect1 参数的 area 函数,现在可以使用方法语法直接对我们的 Rectangle 实例调用 area 方法。方法语法写在实例后面:加点,再跟上方法名、括号及任何参数。

area 的签名里使用 &self 而不是 rectangle: &Rectangle。&self 实际上是 self: &Self 的简写。在 impl 块中,Self 是当前实现块对应类型的别名。所有的方法必须以名字为 self 且类型为 Self 的参数作为首个参数,因此 Rust 允许你只写成 self 来简化书写。但注意仍需加 & 表明此处借用了 Self 实例,就像之前用 rectangle: &Rectangle 一样。方法可以取得 self 所有权,也可以不可变借用自我(如这里),或者可变借用自我,就像对待其它任意参数一样。

这里选择 &self 和之前函数版本里的 &Rectangle 原因相同:不想获取所有权,只想读取结构体数据而非修改。如果希望改变被调用实例,则首个参数应设为 &mut self。而仅以 self 为首参并取得所有权的方法较少见;通常用于将自身转换成另一种东西,从而阻止调用者继续使用原始实例。

除了提供更方便的方法语法、不必每次重复指定自我类型外,使用方法代替普通函数最主要原因是组织性好——把能作用于某一类型实例的一切功能集中放进同一 impl 块,而不用让未来用户去库里各处寻找该类型能力所在。

注意,可以给某个字段起同样名字的方法。例如,可以给 Rectangle 定义一个也叫 width 的方法:

文件名: src/main.rs

impl Rectangle {fn width(&self) -> bool {self.width > 0}
}fn main() {let rect1 = Rectangle {width: 30,height: 50,};if rect1.width() {println!("The rectangle has a nonzero width; it is {}", rect1.width);}
}

这里,我们让宽度(width)这个同名的方法判断如果实例字段width大于0则返回 true,否则 false;即使名称相同,在该命名空间下,该字段依然可用于任何目的。在 main 中,当跟着圆点后带括号时,比如 rect1.width() ,Rust 知道指的是宽度这个“方法”;当没有括号时,比如 rect1.width ,Rust 知道指的是字段本身。

通常但不总是如此,当给字段起同样名字的方法时,这类“getter”只会返回对应字段值,不做其它操作。而 Rust 并不会自动帮 struct 字段生成 getter 方法,这一点与某些语言不同。这类 getter 很实用,因为你可以把字段设置成私有,但公开对应 getter,使得外部只能读不能改,这是设计公共 API 时常见手段。本书将在第7章讲解什么是公有(private)、私有(public),以及如何标记成员访问权限。

-> 操作符去哪儿了?
C 和 C++ 调用对象上的成员或其指针上的成员分别需要 . 和 -> 两种操作符,即若 object 是指针,则 object->something() 等价于 (*object).something() 。

Rust 没有等价于 -> 操作符,而采用了一种称作自动引用和解引用(automatic referencing and dereferencing)的新特性。这也是 Rust 少数几个支持这种行为的位置之一——即调用对象上的某个 method 时,如果签名要求引用或可变引用甚至取值,会自动帮你补充 &, &mut 或 * 。

例如下面两句完全等效:

p1.distance(&p2);
(&p1).distance(&p2);

第一句看起来更简洁。这种自动添加引用行为之所以行得通,是因为每个 method 都明确知道自己的接收者(receiver)—即那个叫做 self 参数的数据类型。有了接收者信息及 method 名称,Rust 能准确推断出这是读取(&self)、修改(&mut self)还是消费(self)。这种隐式借用机制极大提升了拥有权系统实际编程体验的人机友好度。

带有更多参数的方法

让我们通过在 Rectangle 结构体上实现第二个方法来练习使用方法。这次,我们希望 Rectangle 的一个实例接收另一个 Rectangle 实例作为参数,并返回 true,如果第二个矩形可以完全放入第一个矩形(self)内;否则,返回 false。也就是说,一旦定义了 can_hold 方法,我们就能像清单 5-14 中那样编写程序。

文件名:src/main.rs

fn main() {let rect1 = Rectangle {width: 30,height: 50,};let rect2 = Rectangle {width: 10,height: 40,};let rect3 = Rectangle {width: 60,height: 45,};println!("Can rect1 hold rect2?{}", rect1.can_hold(&rect2));println!("Can rect1 hold rect3?{}", rect1.can_hold(&rect3));
}

清单 5-14:使用尚未编写的 can_hold 方法
预期输出如下,因为 rect2 的两个维度都小于 rect1,而 rect3 比 rect1 宽:

Can rect1 hold rect2? true
Can rect1 hold rect3? false

我们知道要定义一个方法,所以它会在 impl Rectangle 块中。方法名为 can_hold,它将接受另一个不可变借用的 Rectangle 参数。通过查看调用该方法的代码可知参数类型:rect1.can_hold(&rect2)传入的是 &rect2,这是对 rect2(Rectangle 实例)的不可变借用。这很合理,因为我们只需要读取 rect2(而非修改,需要可变借用),且希望 main 保留对 rect2 的所有权,以便调用完 can_hold 后还能继续使用它。can_hold 返回值是布尔型,实现时检查 self 的宽和高是否分别大于另一个矩形的宽和高。让我们把新的 can_hold 方法添加到清单 5-13 中的 impl 块,如清单 5-15 所示。

文件名:src/main.rs

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}
}

清单 5-15:为接受另一个 Rectangle 实例作为参数的 can_hold 方法实现

当运行包含清单 5-14 中 main 函数的代码时,将得到期望输出。方法可以接受多个参数,这些参数加在 self 参数之后,其工作方式与函数中的参数相同。

关联函数

所有定义在 impl 块中的函数称为关联函数,因为它们与 impl 后面的类型相关联。我们可以定义不以 self 为首个参数(因此不是方法)的关联函数,因为这些函数不需要某个类型实例即可工作。例如,我们已经使用过 String 类型上的 String::from 函数就是这样一种关联函数。

非方法形式的关联函数通常用于构造器,用来返回结构体的新实例。这类构造器常被命名为 new,但 new 并不是特殊名称,也没有内置于语言中。例如,我们可以提供一个名为 square 的关联函数,它只有一个尺寸参数,并将其同时赋给宽和高,从而更方便地创建正方形矩形,而无需重复指定相同值:

文件名:src/main.rs

impl Rectangle {fn square(size: u32) -> Self {Self {width: size,height: size,}}
}

Self 在返回类型及函数体中是对 impl 后面出现类型(此处即 Rectangle)的别名。

调用这个关联函数时,使用 :: 符号连接结构体名称,例如 let sq = Rectangle::square(3); 。该功能由结构体命名空间限定符管理;:: 符号既用于关联函数,也用于模块创建命名空间。本书第7章将讨论模块内容。

多个 impl 块

每个结构体允许拥有多个 impl 块。例如,清单5-15等价于下面分开各自实现每个方法的代码,如清单5-16所示:

impl Rectangle {fn area(&self) -> u32 {self.width * self.height}
}impl Rectangle {fncan_hold(&self, other:&Rectangle)->bool{self.width>other.width&&self.height>other.height}
}

清单5-16:用多个impl块重写清单5-15

这里没必要拆分成多个impl块,但这种语法是合法的。在第10章讲解泛型和特征时,会看到多重impl块派上用场的时候。

总结

结构体让你能够创建符合领域需求、自定义含义的数据类型。利用结构体,可以把相关数据组合起来并给每部分命名,使代码更加明晰。在 impl 块里,你能定义与该类型相关联的方法,其中“方法”是一种特殊形式、绑定到具体实例行为上的关联函 数。但自定义数据类型不仅限于struct,让我们转向 Rust 枚举(enum),再增加一项强力工具吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90426.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90426.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/90426.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】C++ 的入门语法知识1

本文主要讲解C语言的入门知识,包括命名空间、C的输入与输出、缺省参数以及函数重载。 目录 1 C的第一个程序 2 命名空间 1) 命名空间存在的意义 2) 命名空间的定义 3) 命名空间的使用 3 C的输出与输入 1) C中…

SpringBoot6-10(黑马)

JWT令牌简介:1.JWT全称:JSON Web Token(https://iwt.io/)定义了一种简洁的、自包含的格式,用于通信双方以json数据格式安全的传输信息。2.组成: >第一部分:Header(头),记录令牌类型、签名算法等。例如:("alg":“HS256",“t…

智能制造场景195个术语的16个分类

说明:《智能制造典型场景参考指引(2025年版)》日前,由工信部办公厅正式发布,将成为众多制造型企业的工作纲领 1. 工厂数字化规划设计(1.1):在电脑上用专业软件设计工厂布局、规划生产…

[论文阅读] 人工智能 + 软件工程 | 微信闭源代码库中的RAG代码补全:揭秘工业级场景下的检索增强生成技术

微信闭源代码库中的RAG代码补全:揭秘工业级场景下的检索增强生成技术 论文标题:A Deep Dive into Retrieval-Augmented Generation for Code Completion: Experience on WeChatarXiv:2507.18515 A Deep Dive into Retrieval-Augmented Generation for Co…

RabbitMQ—仲裁队列

上篇文章: RabbitMQ集群搭建https://blog.csdn.net/sniper_fandc/article/details/149312481?fromshareblogdetail&sharetypeblogdetail&sharerId149312481&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 Raft一致性算法…

[2025CVPR-目标检测方向] CorrBEV:多视图3D物体检测

1. ​研究背景与动机​ 论文关注自动驾驶中相机仅有的多视图3D物体检测(camera-only multi-view 3D object detection)问题。尽管基于鸟瞰图(BEV)的建模近年来取得显著进展(如BEVFormer和SparseBEV等基准模型&#xf…

oracle 数据库批量变更数据 将a表字段批量更新为b表字段

需求:将excel表中的数据批量更新到 taccoinfo表中vc_broker字段0、备份:create table taccoinfo0724 as select vc_custno ,vc_broker from taccoinfo 1、创建临时表: create table taccoinfo0724_1 as select vc_custno ,vc_broker from…

vim-xcode 项目常见问题解决方案

vim-xcode 项目常见问题解决方案 项目基础介绍 vim-xcode 是一个开源项目,旨在通过 Vim 编辑器与 Xcode 项目进行交互。该项目允许开发者在 Vim 中直接构建、测试和运行 Xcode 项目,从而提高开发效率。vim-xcode 主要使用 Vimscript 编写,并依…

个性化网页计数器

需要一个服务器环境来存放我们的计数器脚本和数据库。对于初学者来说,PHP和MySQL是一个不错的组合,因为它们易于学习且广泛应用。接下来,我们开始编写PHP脚本。这个脚本的主要任务是接收来自网页的请求,并将访问信息存储到数据库中…

详解力扣高频SQL50题之1683. 无效的推文【入门】

传送门:1683. 无效的推文 题目 表:Tweets ----------------------- | Column Name | Type | ----------------------- | tweet_id | int | | content | varchar | ----------------------- 在 SQL 中,tweet_id 是这个表的主键。 content 只…

Spring Boot与Python的联动:实战案例解析

目录一、背景与需求二、技术准备2.1 Spring Boot 基础2.2 Python 环境搭建三、基于 RESTful API 的调用3.1 创建 Python Flask 应用3.2 创建 Spring Boot 应用3.3 测试与验证四、通过 ProcessBuilder 调用 Python 脚本4.1 创建 Python 脚本4.2 Spring Boot 中调用脚本4.3 注意事…

力扣刷题(第九十七天)

灵感来源 - 保持更新,努力学习- python脚本学习密钥格式化解题思路移除原字符串中的所有破折号,并将小写字母转换为大写。从后向前遍历处理后的字符串,每 K 个字符为一组。最后将各组逆序拼接,并用破折号分隔。class Solution:def…

ESP32入门实战:PC远程控制LED灯完整指南

引言:物联网远程控制基础 远程控制是物联网应用的基础功能之一,通过ESP32实现PC远程控制LED灯不仅是一个经典入门项目,更是理解网络通信、嵌入式开发和物联网交互的绝佳实践。本文将详细介绍如何通过WiFi和UDP协议,从零开始构建一…

主流摄像头协议及其开源情况,GB/T 28181协议介绍

一、主流摄像头协议及开源情况 1. RTSP(Real Time Streaming Protocol) 技术特性:基于TCP/UDP的实时流传输协议,支持双向通信(如暂停、播放控制)。应用场景:摄像头实时监控、视频点播系统。开源…

「iOS」——RunLoop学习

底层学习iOS--RunLoop学习RunLoop的概念RunLoop与线程的关系RunLoop的结构ModeObserverTimerSourceRunLoop 执行流程RunLoop 的应用1.AutoreleasePool是什么时候释放的2.触控事件的响应3.刷新界面4.线程保活小知识mach Port**Toll-Free Bridging(对象桥接&#xff0…

从零构建 Node20+pnpm+pm2 环境镜像:基于 Dockerfile 的两种方案及持久化配置指南

前言:在Node.js项目部署中,环境一致性和服务自动恢复是运维的核心需求。无论是本地开发还是生产部署,使用Docker封装Node20、pnpm(高效包管理)和pm2(进程守护)环境,能避免“本地能跑…

【Python机器学习】4.3. 模型优化

喜欢的话别忘了点赞、收藏加关注哦(关注即可查看全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 4.3.1. 实战中会遇到的问题 首先看一个例子: 根据任检测数据x1x_1x1​、x2x_2x2…

Impact rating 影响等级定义(学习笔记)

影响等级可以通过四个方面定义,包含安全性safety,经济型financial,操作性operational,和私密性privacy 即[S,F,O,P]这四个方面。每个方面又可以定义四个不同的等级,包含severe(严重的)&#xff…

同花顺前端潜在面试题目与答案

潜在面试题目与答案 以下是根据您提供的“岗位职责”和“岗位要求”整理出的潜在面试题目和参考答案。请注意,这些答案仅供参考,您需要根据自己的实际经验和理解进行更详细和个性化的阐述。 一、基础技术知识(Vue/前端工程化/HTML/CSS/JS&…

J2EE模式---组合实体模式

组合实体模式基础概念组合实体模式(Composite Entity Pattern)是一种企业级设计模式,属于 J2EE 模式的一种,其核心思想是将多个实体对象组合成一个更高层次的对象(组合实体),以简化客户端与这些…