Rust语言入门教程(八) - 引用与借用

上一章的内容中我们讨论了Rust的所有权系统,当我们不想移动值的所有权时,我们可以使用引用和借用,而这正是本章想要讨论的问题。

引用(References)

引用允许你访问或修改数据而无需获取数据的所有权。在 Rust 中,有两种类型的引用:

  • 不可变引用(&T):
    1. 它允许你读取数据,但不能修改它。
    2. 你可以同时拥有多个不可变引用。
    3. 当存在不可变引用时,不能再有可变引用。
  • 可变引用(&mut T):
    1. 它允许你读取和修改数据。
    2. 同一时间,只能有一个可变引用指向同一数据。
    3. 当存在可变引用时,不能再有其他可变或不可变引用,为了防止写竞争或读取数据时数据改变。

请添加图片描述
如上图所示, 在多个线程中如果都存在对同一个值的引用时, 在没有锁的情况下, 对同一个变量进行多个可变引用显然是不安全的。

借用(Borrowing)

借用是指使用引用来访问数据的行为。当你创建一个引用时,实际上是在“借用”值。借用规则如下:

  • 数据的所有者不变:当你借用一个值时,该值的所有权不会转移。
  • 作用域和生命周期:引用必须在其所指向的数据的作用域内有效。这就是 Rust 中的生命周期(lifetime)概念。

引用使用示例

let s1 = String::from("abc");
do_stuff(&s1);
println!("{}", s1);fn do_stuff(s: &String) {// do stuff
}

上面的代码中, 我们还是创建了一个do_stuff()函数, 与上一章不同的是, 我们这个函数接受的参数是一个字符串的引用, &String前面的&符号,表示这是一个String类型的引用, 因此,当调用该函数时,我们传递给他的是对s1的引用, 而s1依然保留了对它的值的所有权。do_stuff()借用了一个对值的引用,它将引用而不是值移动到了函数中, 在函数的作用域结束时, 引用被销毁,我们的借用行为也在此时结束。在函数执行完以后,我们还可以正常的使用s1, 因为其值的所有权没有被移动过。

从内存的视角出发, 当创建一个指向s1的引用时, Rust会创建一个指向s1的指针。 但在Rust中,我们几乎从来不会谈论指针的行为,因为Rust语言在很大程度上会自动处理他们的创建和销毁,Rust中的有一个生命周期的概念,就是用来确保指针始终有效。
请添加图片描述
Rust的编译器可以保证, 不会让用户创建一个引用的存活时间超过它引用的源数据的存活时间,并且指针永远不能指向Null。

可变与不可变引用

引用与变量一样, 默认是不可变的,这意味着,即使被引用的值是可变的,也不能直接通过引用来修改它,例如下面这段代码:

let mut s1 = String::from("abc");
do_stuff(&s1);fn do_stuff(s: &String) {s.insert_str(0, "Hi, "); // Error
}

虽然s1被声明为可变的, 但是它的引用默认是不可变的,因此在函数中试图修改s1的值,编译器就会报错。想要通过引用修改被引用的值,可以将引用声明为可变引用:

let mut s1 = String::from("abc");
do_stuff(&mut s1);fn do_stuff(s: &mut String) {s.insert_str(0, "Hi, ");
}

注意可变引用的格式有些许特别: &mut 变量/类型

解引用

注意到了吗,在上面的例子中的函数中,修改s的值的时候,并没有对其先解引用。我们直接使用了.操作符来访问可变引用上的字符串函数,就像我们在对被引用的值本身进行操作一样。

在Rust中,函数或字段的.运算符会自动对引用进行解引用,获取到最终被引用的值。这样的话,在我们使用.运算符的时候,就不用费劲搞清楚某个变量到底是一个值,还是一个引用,甚至是一个引用的引用了。

那怎么样可以手动的进行解引用的操作呢,和大多数语言一样,在前面加上一个*即可, 解引用操作符的优先级很低,因此需要加上( )

let mut s1 = String::from("abc");
do_stuff(&mut s1);fn do_stuff(s: &mut String) {(*s).insert_str(0, "Hi, ");
}

注意上面说的是在.运算符的情况下, Rust会进行自动的解引用, 对于大多数的其他运算符,例如赋值运算,是需要手动进行解引用的:

let mut s1 = String::from("abc");
do_stuff(&mut s1);fn do_stuff(s: &mut String) {s.insert_str(0, "Hi, ");*s = String::from("Replacement");
}

小结

本章介绍了引用和借用的含义,以及使用方法,让我们来简单回顾一下:

x 			// 变量
&x 			//变量的不可变引用
&mut x 		// 变量的可变引用i32			// 类型
&i32 		// 该类型的不可变引用的类型
&mut i32 	// 该类型的可变引用的类型x: &mut i32 // x是某个值的可变引用
*x			// *x解引用获取到被引用的值, 可变x: &i32		// x是某个值的不可变引用
*x			// 解引用获取到被引用的值,不可变

下一章将开始介绍Rust中的结构体。

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

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

相关文章

阿里云MQTT: 子设备上线流程

0. 背景 阿里云网关子设备上平台的资料很少。有些厂家直接配置每个子设备的DeviceSecret到网关里,显然太麻烦了!我经过阅读阿里文档,发现有些简化的方法,更便于客户使用,因此分享给大家。 1. 主要信息片段 子设备 $…

基于springboot+mysql实现的小区物业管理系统

基于springbootmysql实现的小区物业管理系统,演示地址:登录 演示账号:用户名:744621980qq.com 密码:123456,主要包含房屋管理(楼栋管理,单元管理,房屋管理),车位管理,缴费管理,社区服务( 公告管理&#xf…

Linux socket编程(6):IO复用之select原理及例子

文章目录 1 五种I/O模型1.1 阻塞I/O模型1.2 非阻塞I/O模型1.3 I/O复用模型1.4 信号驱动I/O模型1.5 异步I/O模型 2 select函数3 select实战:实现多个套接字监听3.1 客户端3.2 服务端3.3 实验结果3.4 完整代码 在之前的网络编程中,我们遇到了一个问题&…

Qt TCP网络上位机的设计(通过网络编程与下位机结合)

目录 TCP 协议基础 QTcpServer 和 QAbstractSocket 主要接口函数 TCP 应用程序 1.服务端 2.客户端 上位机通过网络编程与下位机实现通信 TCP 协议基础 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于…

mysql从库设置为只读

直奔主题,mysql设置为只读后,无法增删改。 设置命令: mysql> set global read_only1; #1是只读,0是读写 mysql> show global variables like %read_only%; 以下是相关说明: 1、对于数据库读写状态&#xf…

详解RT-DETR网络结构/数据集获取/环境搭建/训练/推理/验证/导出/部署

论文地址:RT-DETR论文地址 代码地址:RT-DETR官方下载地址 目录 一、本文介绍 二、RT-DETR的网络结构 2.1、模型概览 2.2、高效混合编码器 2.3、IoU感知查询选择 2.4、 可扩展的RT-DETR 三、RT-DERT的环境搭建 四、免费数据集获取 五、获取RT-D…

爬楼梯(力扣LeetCode)动态规划

爬楼梯 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1 阶 1 阶2 阶 示…

使用python 实现华为设备的SFTP文件传输

实验目的: 公司有一台CE12800的设备,管理地址位172.16.1.2,现在需要编写自动化脚本,通过SFTP实现简单的上传下载操作。 实验拓扑: 实验步骤: 步骤1:将本地电脑和ensp的设备进行桥接&#xff…

菜单的hover不同动画背景

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧,主要包含CSS布局,CSS特效,CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点,CSS特效主要是一些动画示例,CSS花边是描述了一些CSS…

SWT/Jface(3): 表格中添加超链接

背景 实际业务中经常需要展示某个网站, 并且希望在展示的时候单击网站可直接访问, 本节演示在表格中如何添加超链接支持. 需求 假设我需要渲染一个Study类, 它只有三个属性id,name和website, 其中id只支持展示, name只支持编辑, 而website只支持单击时跳转到相应的网站, 效果…

Linux7设置ssh秘钥登录并关闭密码登录

说明:场景为windows使用WinScp远程登录linux服务 winscp安装教程:winscp安装及关联putty使用_putty.exe没有找到_cherishSpring的博客-CSDN博客 1.在window上生成公钥和秘钥,操作方式参考以下文章第3点: git关联云效使用教程_云…

Ps:使用钢笔工具绘制自由路径的技巧

只有熟练掌握使用钢笔工具绘制自由路径的技巧,才能快速完成复杂形状的创建以及精准抠图等工作。 钢笔工具是 Photoshop 中绘制路径的主要工具。无论是直线路径还是曲线路径,钢笔工具都能够提供高度的控制和精确度。 ◆ ◆ ◆ 绘制直线路径 绘制直线路径…

下载网页内容成HTML文件

今天遇到了一个非常好用的、开源的网页下载插件: SingleFile,它可以将当前网页里的文字、图片、超链接等,合并成单一的.html文件,便于保存和浏览查看。下面介绍SingleFile的安装和使用。 1、下载SingleFile插件 SingleFile官网地址&#xff…

高并发系统:它的通用设计方法是什么?

Java全能学习面试指南:https://javaxiaobear.cn 我们知道,高并发代表着大流量,高并发系统设计的魅力就在于我们能够凭借自己的聪明才智设计巧妙的方案,从而抵抗巨大流量的冲击,带给用户更好的使用体验。这些方案好似能…

Mybatis-Plus 租户使用

Mybatis-Plus 租户使用 文章目录 Mybatis-Plus 租户使用一. 前言1.1 租户存在的意义1.2 租户框架 二. Mybatis-plus 租户2.1 租户处理器2.2 前置准备1. 依赖2. 表及数据准备3. 代码生成器 2.3 使用 三. 深入使用3.1 前言3.2 租户主体设值,取值3.3 部分表全量db操作3…

【古诗生成AI实战】之三——任务加载器与预处理器

本章内容属于数据处理阶段,将分别介绍任务加载器task和预处理器processor。 [1] 数据集 在深入探讨数据处理的具体步骤之前,让我们先了解一下我们将要使用的数据集的形式。 本项目采用的是七绝数据集,总计83072条古诗,其形式如下&…

大语言模型损失函数详解

我们可以把语言模型分为两类: 自动回归式语言模型:自动回归式语言模型在本质上是单向的,也就是说,它只沿着一个方向阅读句子。正向(从左到右)预测;反向(从右到左)预测。…

linux复习笔记04(小滴课堂)

软件安装rpm方式介绍: 先去挂载光盘: 要确保这是已连接状态。 我们查看到已经挂载成功了。 进到这个目录下。 我们可以看到这有很多rpm软件包。 man rpm: 可以看到很多参数,但是我们不需要全部掌握。 举例: 这就是告诉我们需要安…

2017年五一杯数学建模C题宜居城市问题值解题全过程文档及程序

2017年五一杯数学建模 C题 宜居城市问题 原题再现 城市宜居性是当前城市科学研究领域的热点议题之一,也是政府和城市居民密切关注的焦点。建设宜居城市已成为现阶段我国城市发展的重要目标,对提升城市居民生活质量、完善城市功能和提高城市运行效率具有重要意义。…

深信服超融合一体机提示:内存ECC

PS:此事件分享主要来源于季度巡检时发现的超融合一体机红灯闪烁异常,接入IPMI端口查看日志发现持续提示内存ECC; 因为是只有3.05这一天发现了有这个告警的提示,所以当时清除了日志以后重启了BMC服务就解决了;但是如果清…