【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就指的是Rectanglearea的参数不用拿走所有权,所以在self前面加上&表示印引用。

当然这么改之后,main函数里的函数调用也会改,从函数的调用改到方法的调用——实例.方法名(参数):

fn main() {  let rectangle = Rectangle{  width: 30,  length: 50,  };  println!("{}", rectangle.area());  
}

rectangle.area()的括号中不写东西是因为area方法在定义时只使用了&self作为参数,表示这个方法借用了self(即rectangle实例)的不可变引用。在调用area时,你不需要显式地传递这个实例,因为方法调用已经隐式地知道selfrectangle

整体代码如下:

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

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

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

相关文章

springboot vue 会员营销系统

springboot vue 会员营销系统介绍 演示地址: 开源版本:http://8.146.211.120:8083/ 完整版本:http://8.146.211.120:8086/ 移动端 http://8.146.211.120:8087/ 简介 欢迎使用springboot vue会员营销系统。本项目包含会员储值卡、套餐卡、计…

HarmonyOS NEXT 技术实践-基于意图框架服务实现智能分发

在智能设备的交互中,如何准确理解并及时响应用户需求,成为提升用户体验的关键。HarmonyOS Next 的意图框架服务(Intents Kit)为这一目标提供了强大的技术支持。本文将通过一个项目实现的示例,展示如何使用意图框架服务…

sfnt-pingpong -测试网络性能和延迟的工具

sfnt-pingpong 是一个用于测试网络性能和延迟的工具,通常用于测量不同网络环境下的数据包传输性能、吞吐量、延迟等指标。 它通常是基于某种网络协议(如 TCP)执行“ping-pong”式的测试,即客户端和服务器之间相互发送数据包&…

前端下载文件的几种方式使用Blob下载文件

前端下载文件的几种方式 使用Blob下载文件 在前端下载文件是个很通用的需求,一般后端会提供下载的方式有两种: 1.直接返回文件的网络地址(一般用在静态文件上,比如图片以及各种音视频资源等) 2.返回文件流(…

智能座舱进阶-应用框架层-Jetpack主要组件

Jetpack的分类 1. DataBinding:以声明方式将可观察数据绑定到界面元素,通常和ViewModel配合使用。 2. Lifecycle:用于管理Activity和Fragment的生命周期,可帮助开发者生成更易于维护的轻量级代码。 3. LiveData: 在底层数据库更…

知乎 PB 级别 TiDB 数据库集群管控实践

以下文章来源于知乎技术专栏 ,作者代晓磊 导读 在现代企业中,数据库的运维管理至关重要,特别是面对分布式数据库的复杂性和大规模集群的挑战。作为一款兼容 MySQL 协议的分布式关系型数据库,TiDB 在高可用、高扩展性和强一致性方…

SpringBoot 自动装配原理及源码解析

目录 一、引言 二、什么是 Spring Boot 的自动装配 三、自动装配的核心注解解析 3.1 SpringBootApplication 注解 (1)SpringBootConfiguration: (2)EnableAutoConfiguration: (3&#xf…

C++中的字符串实现

短字符串优化(SSO) 实现1 实现2 写时复制 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cstring> #include<cstring> using std::cout; using std::endl;// 引用计数存放的位置 // 1. 存放在栈上 --- 不行 // 2. 存…

Linux 基本使用和程序部署

1. Linux 环境搭建 1.1 环境搭建方式 主要有 4 种&#xff1a; 直接安装在物理机上。但是Linux桌面使用起来非常不友好&#xff0c;所以不建议。[不推荐]。使用虚拟机软件&#xff0c;将Linux搭建在虚拟机上。但是由于当前的虚拟机软件(如VMWare之类的)存在一些bug&#xff…

环网冗余CAN转光纤 CAN光端机在风电项目应用

在风力发电项目中&#xff0c;所有的风机内部的状态都需要能够在中控室备被监控到&#xff0c;不论是风机的工作状态还是风机内部的消防状态&#xff0c;以便中控室的工作人员都够根据观测到的信息及时的做出反应&#xff0c;避免造成重大损失。 通常风机的工作信息通过将网口…

ubuntu 如何重装你的apt【apt-get报错: symbol lookup error/undefined symbol】

副标题:解决error:apt-get: symbol lookup error: /lib/x86_64-linux-gnu/libapt-private.so.0.0: undefined symbol: _ZNK13pkgTagSection7FindULLENS_3KeyERKy, version APTPKG_6.0 文章目录 问题描述报错分析解决方案:重装你的apt1、查看你的ubuntu版本2、下载适配你的ap…

网络管理 详细讲解

讲一下之前获取CPU的&#xff0c;其余的原理和这个一样 python代码 app.route(/cpu/) def cpu_used():cpuoidObjectType(ObjectIdentity(myOIDs[cpu_loads]))ret getTableRows((cpuoid,))cpuload0for i in ret:cpuload i[0]print(cpuload)return {cpu:cpuload} var dom do…

用Python PySide6 复刻了两软件UI 做下练习

图样 1 代码 1&#xff1a; # -*- coding: utf-8 -*-import sys from PySide6.QtCore import (QCoreApplication, QMetaObject, QRect, QDate) from PySide6.QtGui import QIcon, QPixmap, QColor from PySide6.QtWidgets import (QApplication, QDialog, QLineEdit, QPushBut…

【day14】异常处理与Object类深入解析

【day13】回顾 在深入探讨异常处理与Object类之前&#xff0c;让我们回顾一下【day13】中的关键内容&#xff1a; 权限修饰符&#xff1a; public&#xff1a;最广的访问范围&#xff0c;任何地方都可以访问。protected&#xff1a;在同包和子类中可以访问。默认&#xff08;无…

题解 洛谷 Luogu P1135 奇怪的电梯 广度优先搜索 BFS C/C++

题目传送门&#xff1a; P1135 奇怪的电梯 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1135思路&#xff1a; 一道比较裸的 BFS&#xff0c;就是把走迷宫每次搜周围相邻四格&#xff0c;改成了楼层每次搜上下方向的某层而已 感觉这个题难度只有普及- …

苏黎世联邦理工学院与加州大学伯克利分校推出MaxInfoRL:平衡内在与外在探索的全新强化学习框架

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ

Q1、统计符合条件长度为3的子数组数目 1、题目描述 给你一个整数数组 nums &#xff0c;请你返回长度为 3 的子数组&#xff0c;满足第一个数和第三个数的和恰好为第二个数的一半。 子数组 指的是一个数组中连续 非空 的元素序列。 2、解题思路 我们需要在给定的数组 nums…

【RAG实战】Prompting vs. RAG vs. Finetuning: 如何选择LLM应用选择最佳方案

在构建基于大型语言模型&#xff08;LLM&#xff09;的应用时&#xff0c;通常不可能立即使用模型而无需任何调整。为了保持高实用性&#xff0c;我们可以选择以下几种方法之一&#xff1a; Prompt Engineering&#xff08;提示工程&#xff09;Fine-tuning&#xff08;微调&a…

Odoo:免费开源ERP的AI技术赋能出海企业电子商务应用介绍

概述 伴随电子商务的持续演进&#xff0c;客户对于便利性、速度以及个性化服务的期许急剧攀升。企业务必要探寻创新之途径&#xff0c;以强化自身运营&#xff0c;并优化购物体验。达成此目标的最为行之有效的方式之一&#xff0c;便是将 AI 呼叫助手融入您的电子商务平台。我们…

如何打造用户友好的维护页面:6个创意提升WordPress网站体验

在网站运营中&#xff0c;无论是个人博主还是大型企业网站的管理员&#xff0c;难免会遇到需要维护的情况。无论是服务器迁移、插件更新&#xff0c;还是突发的技术故障&#xff0c;都可能导致网站短暂无法访问。这时&#xff0c;设计维护页面能很好的缓解用户的不满&#xff0…