【Rust自学】5.3. struct的方法(Method)
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
5.3.1. 什么是方法(Method)
方法和函数类似,也是用fn
关键字进行声明,方法也有名称,也有参数,也有返回值。但方法和函数也有不同之处:
- 方法在struct(或枚举或trait对象)的上下文中定义
- 方法的第一个参数总是
self
,表示方法所在的(被调用的)struct实例,类似于Python中的self
和JS中的this
。
5.3.2. 方法的实际应用
接下来还是看例子,以上一篇文章的代码为例:
struct Rectangle { width: u32, length: u32,
} fn main() { let rectangle = Rectangle{ width: 30, length: 50, }; println!("{}", area(&rectangle));
} fn area(dim:&Rectangle) -> u32 { dim.width * dim.length
}
area
这个函数的作用是计算面积,但它很特别,它只适用于矩形而不适用于其他形状或者是其他的类型。如果后面代码中要加上计算其他图形的面积的函数,那么area
这个名字就要混淆。如果改名成ractangle_area
的话又太麻烦,main
函数里所有调用了这个函数的地方都要改。
所以如果能把存储矩形长款的Rectangle
结构体和只能计算矩形面积area
这个函数结合到一起就是最好的。
对于这种需求,Rust提供了implementation
(中文意为实现),其关键字是impl
,后边跟着struct名,加上{}
,在里面像定义普通函数一样定义方法就行。
对于这个例子,struct名就是Rectangle
,把定义area
函数的代码剪贴到{}
内即可。
impl Rectangle { fn area(dim:&Rectangle) -> u32 { dim.width * dim.length }
}
但注意这里的代码还不是方法,因为方法的第一个参数必须是self
,现在的代码叫关联函数,下文会讲。
这么写是没有问题的,但还可以进一步简化。上文中说到了方法的第一个参数总是self
,所以这里也可以改一下:
impl Rectangle { fn area(&self) -> u32 { self.width * self.length }
}
你当前写的这个方法绑定在谁上,self
指的就是谁,这个代码中area
这个函数被绑定在Rectangle
上,所以self
就指的是Rectangle
,area
的参数不用拿走所有权,所以在self
前面加上&
表示印引用。
当然这么改之后,main
函数里的函数调用也会改,从函数的调用改到方法的调用——实例.方法名(参数)
:
fn main() { let rectangle = Rectangle{ width: 30, length: 50, }; println!("{}", rectangle.area());
}
rectangle.area()
的括号中不写东西是因为area
方法在定义时只使用了&self
作为参数,表示这个方法借用了self
(即rectangle
实例)的不可变引用。在调用area
时,你不需要显式地传递这个实例,因为方法调用已经隐式地知道self
是rectangle
。
整体代码如下:
struct Rectangle { width: u32, length: u32,
} impl Rectangle { fn area(&self) -> u32 { self.width * self.length }
} fn main() { let rectangle = Rectangle{ width: 30, length: 50, }; println!("{}", rectangle.area());
}
输出:
1500
5.3.3. 如何定义方法
在上面的实际应用中已经写过一遍了,所以这里就只做总结:
- 在
impl
里定义方法 - 方法的第一个参数可以是
self
、&self
或是&mut self
。可以是获得所有权、引用或可变引用,这点和其他参数一样。 - 方法可以帮助更好的组织代码,因为可以把某个类型的方法都放在
impl
块里面,避免在整个代码库里搜索struct它相关的行为了。
5.3.4. 方法调用的运算符
在C/C++中,调用方法有两种运算符
->
:其格式为object->something()
,调用指针指向的对象上的方法就使用这一种(也就是object
为指针时).
:其格式为object.something()
,调用对象上的方法就使用这种(也就是object
不为指针,是个对象时)
而object->something()
实际上是语法糖,它等同于(*object).something()
,*
表示解引用。两者的流程都是先解引用,得到对象,再在对象上调用方法。
Rust提供了自动引用/解引用的特性。也就是说,在调用方法时,Rust根据情况自动添加&
、&mut
或*
,以便object
可以匹配方法的签名。这点和Go语言一样。
举个例子,下面这两行代码效果相同:
point1.distance(&point2);
(&point1).distance(&point2);
Rust会根据情况自动在point1
前加上&
。
5.3.5. 方法的参数
方法除了self
也可以带其他参数,一个或多个都可以。
举个例子,在5.3.2的代码基础上加一个判断矩形是否能容纳下另一个长方形的功能(不考虑斜着放,也不考虑矩形的长比宽长的情况)
impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.length > other.length }
}
逻辑非常好想,只要矩形的长和宽都比另一个大就行。
然后再在main
函数里写几个Rectangle
的实例,输出比较结果看看有没有问题就行,以下是完整代码:
struct Rectangle { width: u32, length: u32,
} impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.length > other.length }
} fn main() { let rect1 = Rectangle{ width: 30, length: 50, }; let rect2 = Rectangle{ width: 10, length: 40, }; println!("{}", rect1.can_hold(&rect2));
}
输出:
true
5.3.6. 关联函数
可以在impl
块里定义不把self
作为第一个参数的函数,叫关联函数(不是方法)。它不是在实例上调用的,但它与这个类型有关联。例如: String::from()
就是String
这个类型上叫做from
的关联函数。
关联函数通常用于构造器,也就是用来被创建关联类型的一个实例。
比如说,在5.3.2的代码基础上加一个构建正方形的构造器(正方形也是特殊的矩形):
impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle{ width: size, length: size, } }
}
参数只需要一个,因为构造正方形只需要一个边长。
在main
函数里调用一下这个关联函数试试,其格式为类型名::函数名(参数)
,以下是完整代码:
#[derive(Debug)]
struct Rectangle { width: u32, length: u32,
} impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle{ width: size, length: size, } }
} fn main() { let square = Rectangle::square(10); println!("{:?}", square);
}
输出:
Rectangle { width: 10, length: 10 }
::
不仅可以用于关联函数,也可以用于模块创建命名空间(以后会讲)
5.3.7. 多个impl块
每个struct允许拥有多个impl
块。
比如我要把这篇文章里写过的所有的方法和关联函数都写到代码里。
可以这么写(多个impl
块):
#[derive(Debug)]
struct Rectangle { width: u32, length: u32,
} impl Rectangle { fn area(&self) -> u32 { self.width * self.length }
} impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.length > other.length }
} impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle{ width: size, length: size, } }
} fn main() { let square = Rectangle::square(10); println!("{:?}", square);
}
也可以这么写(合在一个impl
块里):
#[derive(Debug)]
struct Rectangle { width: u32, length: u32,
} impl Rectangle { fn area(&self) -> u32 { self.width * self.length } fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.length > other.length } fn square(size: u32) -> Rectangle { Rectangle{ width: size, length: size, } }
} fn main() { let square = Rectangle::square(10); println!("{:?}", square);
}
相关文章:
【Rust自学】5.3. struct的方法(Method)
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 5.3.1. 什么是方法(Method) 方法和函数类似,也是用fn关键字进行声明,方法也有名称,也有参数ÿ…...
ChatGPT之父:奥尔特曼
奥尔特曼 阿尔特曼一般指萨姆奥尔特曼,他是OpenAI的联合创始人兼首席执行官,被称为“ChatGPT之父”.以下是其具体介绍: 个人经历 1985年4月22日出生于美国芝加哥,8岁学会编程,9岁拥有电脑,对信息技术和互联网产生兴趣.高中就读于约翰巴勒斯中学,后进入斯坦福大学主修计…...

如何在谷歌浏览器中设置桌面快捷方式
在日常使用电脑时,反复在浏览器中输入经常访问的网址不仅耗时,而且降低了工作效率。为了解决这一问题,我们可以通过在主屏幕上创建谷歌浏览器的快捷方式来简化操作。本文将详细介绍如何在Windows和Mac系统中实现这一功能。 一、步骤概述 1. …...
systemverilog中的priority if
1 基本概念 在 SystemVerilog 中,priority - if是一种条件判断结构。它和普通的if - else语句类似,但在条件评估和错误检查方面有自己的特点,主要用于按顺序评估多个条件,并且对不符合预期的情况进行报错。报错如下两点 当所有条件…...

图像处理-Ch2-空间域的图像增强
Ch2 空间域的图像增强 文章目录 Ch2 空间域的图像增强Background灰度变换函数(Gray-level Transformation)对数变换(Logarithmic)幂律变换(Power-Law)分段线性变换函数(Piecewise-Linear)对比度拉伸(Contrast-Stretching)灰度级分层(Gray-level Slicing) 直方图处理(Histogram …...
css 编写注意-1-命名约定
编写按照可维护性、性能和可读性规则: 1.代码组织与结构 层次清晰:使用模块化的结构,将样式分块组织。命名规范:采用统一的命名规则(如 BEM、SMACSS)以增强可读性。 /* BEM …...
虚幻引擎反射机制
在虚幻引擎中,反射系统是一种强大的机制,它允许开发者和引擎本身在运行时获取并操作类、对象、属性和方法的元信息。这个系统是基于UObject(Unreal Engine中所有支持反射的对象的基类)构建的,为游戏开发提供了极大的灵…...
Knife4j Swagger
1. 依赖 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></dependency>2. 配置 第二步配置完成就可以访问:http://localhost…...

Xcode 16 编译弹窗问题、编译通过无法,编译通过打包等问题汇总
问题1:打包的过程中不断提示 :codesign 想要访问你的钥匙串中的密钥“develop 或者distribution 证书” 解决:打开钥匙串,点击证书---显示简介---信任----改为始终信任 (记住 :不能只修改钥匙的显示简介的…...
卷积神经网络入门指南:从原理到实践
目录 1 CNN的发展历史 2 CNN的基本原理 3 CNN核心组件 3.1 卷积操作基础 3.2 卷积层详解 3.3 高级卷积操作 3.3.1 分组卷积(Group Convolution) 3.3.2 深度可分离卷积(Depthwise Separable Convolution): 3.3 池…...

eNSP安装教程(内含安装包)
通过网盘分享的文件:eNSP模拟器.zip 链接: https://pan.baidu.com/s/1wPmAr4MV8YBq3U5i3hbhzQ 提取码: tefj --来自百度网盘超级会员v1的分享 !!!!解压后有四个文件,先安装Box,第二个安装cap&a…...

VBA技术资料MF244:利用VBA在图表工作表中创建堆积条形图
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...

【计算机网络安全】网络攻击
实验二 网络攻击 实验人员:第五组全体成员 一、实验目的: 1:掌握ARP欺骗的原理,实践ARP欺骗的过程。 2:掌握TCP劫持的原理,实践TCP劫持的过程。 3:掌握DNS欺骗的原理,实践DN…...
20241230 基础数学-线性代数-(1)求解特征值(numpy, scipy)
所有代码实现,基于教程中的理论通过python实现出来的。效率不高,但有代码可以看。 由于scipy/sckitlearn/sparkx 底层的实现都被封装了(小白兔水平有限,fortran代码实在没看懂)这里的实现至少可以和理论公式对应的上。…...

基于图注意力网络的两阶段图匹配点云配准方法
Two-stage graph matching point cloud registration method based on graph attention network— 基于图注意力网络的两阶段图匹配点云配准方法 从两阶段点云配准方法中找一些图匹配的一些灵感。文章提出了两阶段图匹配点云配准网络(TSGM-Net) TSGM-Ne…...

【半导体光电子器件】课后习题答案和知识点汇总
关注作者了解更多 我的其他CSDN专栏 求职面试 大学英语 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处…...

Unity命令行传递自定义参数 命令行打包
命令行参数增加位置 -executeMethod 某脚本.某方法 参数1 参数2 参数3 ... 例如执行EditorTest.GetCommandLineArgs方法 增加两个命令行参数 Version=125 CDNVersion=100 -executeMethod EditorTest.GetCommandLineArgs Version=125 CDNVersion=100 Unity测试脚本 需要放在…...

web-worker应用在大文件切片上传
当文件体积过大时,传统的文件上传方式往往会导致页面卡顿,用户体验不佳。为了解决这一问题,我们可以利用Web Worker技术来进行大文件的切片上传。本文将详细介绍如何使用Web Worker进行大文件切片上传,并通过具体的例子来演示其实…...
Django 模板分割及多语言支持案例【需求文档】-->【实现方案】
Django 模板分割及多语言支持案例 这个案例旨在提供一个清晰的示范,展示如何将复杂的页面分解为多个可复用的模板组件,使代码更加模块化和易于管理。希望这篇案例文章对你有所帮助。 概述 在 Django 项目开发中,使用模板分割和多语言支持能…...
C中设计不允许继承的类的实现方法是什么?
在C中,设计不允许继承的类可以通过多种方法实现。以下是详细的方法说明及示例: ### 方法一:将构造函数和析构函数设为私有 这种方法的核心思想是通过将构造函数和析构函数设为私有,使得子类无法调用这些函数,从而无法…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...