【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中,设计不允许继承的类可以通过多种方法实现。以下是详细的方法说明及示例: ### 方法一:将构造函数和析构函数设为私有 这种方法的核心思想是通过将构造函数和析构函数设为私有,使得子类无法调用这些函数,从而无法…...

面对小白的C语言学习方法
这是第20篇文章,不来弄一些技术的,弄一些最近的学习心得,怎么更有效地自学C语言 书籍 书籍可以很有效的告知我们专有函数,使用方法还有一些思考方式,缺点是实操差点意思,还是不太能解决实际问题ÿ…...

使用libgif库解码全过程(C语言)-包括扩展块的处理
我看到的所有例程,都把扩展部分的处理跳过了,而我的动画是有透明度的,这就导致解码后的图像在有透明色的像素部分,呈现了很多的黑点,或者闪白的情况出现。经过调试,终于成功。 文件格式 先了解一下GIF的文…...

blazor实现ASP.NET网站用户批量注册方法
ASP.NET网站用户批量注册是许多使用blazor系统开发遇到的问题,为了解决这个问题,我们提出比较完善的解决方法,通过代码实现了一个批量用户注册功能,用于解析一份用户名列表,并通过后台服务注册用户,同时对成功和失败的注册进行记录和反馈。以下是实现功能的详细工作原理描…...

SpringCloud 入门(4)—— 网关
上一篇:SpringCloud 入门(3)—— Nacos配置中心-CSDN博客 Spring Cloud Gateway 作为 Spring Cloud 生态系统的一部分,主要在微服务架构中充当 API 网关的角色。它提供了统一的入口点来处理所有的 HTTP 请求,并将这些请…...

什么是WebAssembly?怎么使用?
一、简述 WebAssembly,也称为Wasm,是基于堆栈的虚拟机的二进制指令格式。它被设计为一个可移植的目标,用于编译C、C和Rust等高级编程语言,允许代码以接近本机速度在web浏览器中运行。WebAssembly于2015年由包括谷歌、微软、Mozill…...

v3s点RGB屏 40pin 800x480,不一样的点屏,不通过chosen。
一、背景、目的、简介。 一般来说,通过uboot将屏幕参数传给kernel,是通过修改设备树。 uboot和kernel都需要屏幕点亮。uboot侧重于显示一张图片。而kernel则多是动画。 在这里,我先是找到了一个裸机点屏的代码。将其编译成静态库后&#x…...

某科技局国产服务器PVE虚拟化技术文档
环境介绍 硬件配置 服务器品牌:黄河 型号:Huanghe 2280 V2 Cpu型号:kunpeng-920 磁盘信息 :480SSD * 2 ,4T*4 网卡:板载四口千兆 如下表 四台服务器同等型号配置,均做单节点虚拟化,数据保护采用底层r…...

中科岩创边坡自动化监测解决方案
行业现状 由于边坡不稳定性因素,可能会造成斜坡上的岩土体沿着某个面不均匀向下向外滑动,形成滑坡;陡峭山坡上岩土体在重力作用下,发生陡然倾落运动,造成崩塌;在沟谷或山坡上产生的夹带大量泥沙、石块等固体…...

GPT-O3:简单介绍
GPT-O3:人工智能领域的重大突破 近日,OpenAI发布了其最新的AI模型GPT-O3,这一模型在AGI评估中取得了惊人的成绩,展现出强大的能力和潜力。GPT-O3的出现标志着人工智能领域的重大进步,预计将在2025年实现更大的突破。 …...

cudnn版本gpu架构
nvcc --help 可以看 --gpu-architecture 写到的支持的架构 NVIDIA 的 GPU 架构是按代次发布的,以下是这些架构的对应说明: NVIDIA Hopper: 这是 NVIDIA 于 2022 年推出的架构之一,面向高性能计算(HPC)和人工智能&…...