【Rust中级教程】1.10. 引用及内部可变性(简单回顾):引用、内部可变性、`Cell`类型及相关操作

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

这篇文章只对所有权进行简单回顾,想要看完整的所有权系统阐述见【Rust自学】专栏的第15章的文章。
请添加图片描述

1.10.1. 引用

通过引用,Rust允许将值借用出去,但不放弃所有权。

引用就是带有附加合约的指针。Rust中一共有两种引用类型。

1. 共享的引用

共享的引用,又叫不可变的引用,Rust中写作&T,其中T指代类型。

它的特点在一可以同时(或者叫在同一作用域内)存在任意数量的引用指向同一个值。每个共享的引用都实现了Copy trait。

共享引用背后的值不可变。编译器允许假定共享引用指向的值,在该引用存货期间是不会改变的。

举个例子:一个共享引用的值在某函数内被多次读取,那编译器就有权让其只读取一次,然后重用读取的值。

2. 可变引用

与不可变引用相对的就是可变引用,在Rust中写作&mut T

可变引用是独占的,意味着在一个作用域内只能有一个可变引用,不能出现第二个可变引用或任意数量的共享引用。所以不可变引用没有实现Copy trait。

编译器会假定没有其它线程访问可变引用所指向的类型(无论是通过共享引用还是可变引用)。

1.10.2. 拥有值 vs. 拥有到值的可变引用

所有者需要对删除值(丢弃值)负责,除此之外两者的作用基本一样。

注意:如果你移动了可变引用背后的值,则必须在其位置上留下另一个值。如果不这样做,所有者会认为它需要将其删除(丢弃),但其实却没有值可以删除了,导致未定义行为编译错误

看个例子:

fn main() {let mut s = String::from("Hello");let r = &mut s;let t = *r;  // 试图移动 r 所指向的值println!("{}", r);  // r 变成了悬垂引用
}

输出:

error[E0507]: cannot move out of `*r` which is behind a mutable reference

我们来梳理一下过程:

  • rs的可变引用,而 *r的操作试图移动这个值(String类型没有实现Copy trait,意味着s会失去数据)
  • 由于s仍然存在,当s作用域结束时,Rust期望可以正常释放它的内存
  • s已经被移动走了,导致Rust不知道该如何正确释放它,从而引发编译错误

正确的做法:

fn main() {let mut s = String::from("Hello");let r = &mut s;let t = std::mem::replace(r, String::new()); // 用空字符串替换原值println!("{}", t);  // "Hello"println!("{}", s);  // ""
}

1.10.3. 内部可变性

一些类型提供了内部可变性,这些类型可以通过共享引用修改值

这些类型通常依赖于额外的机制(如原子CPU指令)或不变量来提供安全的可变形,而不依赖于独占引用的语义。

内部可变性分为两类:

  • 通过共享引用获得可变引用:MutexRefCell(这两者在【Rust自学】专栏的第15章的文章中都介绍过)
    这类类型提供了保障机制——如果对某个值提供了可变引用,那么同时(或者叫在同一作用域下)只会存在一个可变引用,并且没有共享引用。这种功能依赖于UnsafeCell类型,通过共享引用修改值的唯一正确方式。

  • 通过共享引用可以替换值:std::sync::atomicstd::cell::Cell
    这类类型没有提供可变引用到内部的值,但是提供了就地操作值的方法——比如说替换/读取一个值。例如:无法获得到usizei32的直接引用,但是可以读取和替换值。

1.10.4. Cell类型

Cell类型来自于标准库,它通过不变量实现内部可变性。

  • Cell类型无法跨线程共享,因为内部值不会被并发地修改,即使通过共享引用发生修改
  • 不会提供到Cell内部的值的引用(所以可以一直移动它)

Cell提供的方法:

  • 对值整体替换(也就是所谓的就地操作)
  • 返回值的副本(也就是读取)

1. set(value): 替换值

use std::cell::Cell;fn main() {let x = Cell::new(10);  // 创建一个 `Cell`,存储 10x.set(20);  // 替换内部值println!("Updated value: {}", x.get()); // 输出 20
}
  • set(value)新值替换Cell内部的值

2. get():返回值的副本

use std::cell::Cell;fn main() {let x = Cell::new(5);let y = x.get(); // 获取 `x` 内部的副本println!("Value: {}", y); // 输出 5
}
  • get()不会返回内部值的引用,而是返回值的副本(适用于实现Copy trait 的类型)。
  • 适用于i32bool实现Copy trait 的类型

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

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

相关文章

2012年下半年软件设计师上午题知识点及其详细解释(附真题及答案解析)

以下是2012年下半年软件设计师上午题的所有题目(从第1题到第75题)的总结,按顺序列出每道题目的考察知识点及其详细解释,供考生背诵记忆: 1. 控制器 知识点:CPU的组成与功能解释:控制器负责指令…

openGauss 6.0.0 RC1数据库日常运维

引言 随着数字化时代的快速发展,数据库作为企业信息化的核心,其稳定性和性能对于企业至关重要。openGauss 6.0.0 openGauss是一款开源关系型数据库管理系统,采用木兰宽松许可证v2发行。openGauss内核深度融合华为在数据库领域多年的经验&…

4090单卡挑战DeepSeek r1 671b:尝试量化后的心得的分享

引言: 最近,DeepSeek-R1在完全开源的背景下,与OpenAI的O1推理模型展开了激烈竞争,引发了广泛关注。为了让更多本地用户能够运行DeepSeek,我们成功将R1 671B参数模型从720GB压缩至131GB,减少了80%&#xff…

【Scrapy】Scrapy教程6——提取数据

前一小节我们拿到了页面的数据,那页面中那么多内容,我们想要其中的部分内容,该如何获取呢?这就需要对我们下载到的数据进行解析,提取出来想要的数据,这节就讲讲如何提取数据。 引入 我们编辑保存下来的shouye.html文件看下,发现这是什么鬼,全是如下图的代码。 没错…

Python 的 with 语句可以用来管理资源的自动清理,并替代 try...finally 语句,使代码更简洁易读

Python 的 with 语句可以用来管理资源的自动清理,并替代 try...finally 语句,使代码更简洁易读。 1. with 语句的作用 在 Python 里,with 语句通常用于管理资源,比如文件、数据库连接、网络请求等。 它可以保证无论代码是否执行…

栈回溯基础

指令集区分 thumb指令集 长度:thumb指令通常是 16 位。特点:thumb 指令集是为了压缩指令集长度减少程序占用空间。对齐方式:2字节对齐,存放 thumb 指令的地址一般会被1,设置为奇数,用于表示地址上存放的是…

Pytorch论文实现之GAN-C约束鉴别器训练自己的数据集

简介 简介:这次介绍复现的论文主要是约束判别器的函数空间,作者认为原来的损失函数在优化判别器关于真样本和假样本的相对输出缺乏显式约束,因为在实践中,在优化生成器时,鉴别器对生成样本的输出会增加,但对真实数据保持不变,而优化鉴别器会导致其对真实数据的输出增加…

Pyecharts系列课程06——热力图(Heatmap)

1. 基础使用 热力图是一种用于展示数据分布的密度或热度的图表,通过颜色深浅来表示数值大小。 a. 简单示例 我们先来看一个简单示例: 简单示例 from pyecharts.charts import HeatMapx_data = ["分类1", "分类2", "分类3"] y_data

交换路由——控制VLAN之间通信

项目 最近一段时间,A公司发现划分VLAN之后,网速提高很多,发生拥堵的情况消失了.但是,部门之间不能互联,也给办公室带来不便.公司要求项目实施各VLAN内主机互通。 部门 VLAN 名称 端口范围 网络ID 计算机 市场部 VLAN 10 shichang f0/1-f/010 192.168.10.0/24 pc0,pc…

使用 Redis 实现 RBAC 权限管理

1. 什么是 RBAC? RBAC(Role-Based Access Control,基于角色的访问控制)是一种常见的权限管理模型,它通过用户(User)、角色(Role)、权限(Permission&#xff…

qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到view、通过view得scene

qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到view、通过view得scene code review! 文章目录 qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到view、通过view得scene1.`setScene` 方法2.通过 `scene` 获取它的视图 (`views()`)…

DeepSeek频繁宕机应对方案

第三方监测显示,38%的企业因AI工具不稳定错失热点流量(Gartner 2025)。当竞品1小时内发布300篇行业内容时,你可能还在为「服务器繁忙」提示焦头烂额。147SEO系统通过智能容错机制,帮助某本地生活平台稳定输出580篇地域…

CentOS/RHEL如何更换国内Yum源

在国内使用CentOS或RHEL系统时,默认的Yum源是国外的,这可能导致软件包的下载速度慢,甚至出现连接超时的问题。为了解决这个问题,我们可以将Yum源切换到国内的镜像源,从而大大提高软件包的下载速度和稳定性。 本文将详…

cs224w课程学习笔记-第2课

cs224w课程学习笔记-第2课 传统图学习 前言一、节点任务1、任务背景2、特征节点度3、特征节点中心性3.1 特征向量中心性(Eigenvector Centrality)3.2 中介中心性(Betweenness Centrality)3.3 接近中心性(Closeness Cen…

【设计模式】【结构型模式】代理模式(Proxy)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 🎵 当你的天空突…

平板作为电脑拓展屏

有线串流(速度更快) spacedesk 打开usb对安卓的连接 用usb线直接连接电脑和平板 无线串流(延迟高,不推荐) todesk pc和手机端同时下载软件,连接后可以进行远程控制或扩展屏幕 spacedesk 连接到同一个…

[文末数据集]ML.NET库学习010:URL是否具有恶意性分类

文章目录 ML.NET库学习010:URL是否具有恶意性分类项目主要目的和原理项目概述主要功能和步骤总结数据集地址ML.NET库学习010:URL是否具有恶意性分类 项目主要目的和原理 项目主要目的: 本项目的目的是通过分析URL的特征,构建一个机器学习模型来判断给定的URL是否具有恶意…

Zotero PDF Translate插件配置百度翻译api

Zotero PDF Translate插件可以使用几种翻译api,虽然谷歌最好用,但是由于众所周知的原因,不稳定。而cnki有字数限制,有道有时也不行。其他的翻译需要申请密钥。本文以百度为例,进行申请 官方有申请教程: Zot…

具身智能在智能巡检机器人中的应用——以开关柜带电操作机器人为例

随着机器人技术和人工智能的迅速发展,具身智能在各行业的应用日益广泛,尤其是在电力行业中的智能巡检领域。传统的电力巡检和维护工作通常需要人工操作,存在着高温、高压、强电磁场等危险环境,且效率较低。开关柜带电操作机器人作…

网络工程师 (43)IP数据报

前言 IP数据报是互联网传输控制协议(Internet Protocol,IP)的数据报格式,由首部和数据两部分组成。 一、首部 IP数据报的首部是控制部分,包含了数据报传输和处理所需的各种信息。首部可以分为固定部分和可变部分。 固定…