当前位置: 首页 > news >正文

【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 的类型

相关文章:

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

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 这篇文章只对所有权进行简单回顾,想要看完整的所有权系统阐述见【Rust自学】专栏…...

Docker 安装和配置 Nginx 详细图文教程

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template 🌺 仓库主页: GitCode︱ Gitee ︱ Github 💖 欢迎点赞 👍 收藏 ⭐评论 …...

基于Java+Swing+Mysql实现旅游管理信息系统

基于JavaSwingMysql实现旅游管理信息系统 一、系统介绍二、功能展示1.登陆2.注册3.旅游信息查询4.查看游行团信息5.报名6、报名信息管理 三、数据库四、其它1.其他系统实现五.获取源码 一、系统介绍 用户:登陆、注册、旅游信息查询、查看游行团信息、报名 管理员&a…...

使用 Openpyxl 操作 Excel 文件详解

文章目录 安装安装Python3安装 openpyxl 基础操作1. 引入2. 创建工作簿和工作表3. 写入数据4. 保存工作簿5. 加载已存在的Excel6. 读取单元格的值7. 选择工作表 样式和格式化1. 引入2. 设置字体3. 设置边框4. 填充5. 设置数字格式6. 数据验证7. 公式操作 性能优化1. read_only/…...

统信服务器操作系统V20 1070A 安装docker新版本26.1.4

应用场景: 硬件/整机信息:x86平台、深信服超融合平台 OS版本信息:统信V20 1070a 1.获取docker二进制包 链接: https://pan.baidu.com/s/1SukBlra0mQxvslTfFakzGw?pwd5s5y 提取码: 5s5y tar xvf docker-26.1.4.tgz groupadd docker ch…...

【数据分享】1929-2024年全球站点的逐年降雪深度数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、能见度等指标,说到气象数据,最详细的气象数据是具体到气象监测站点的数据! 有关气象指标的监测站点数据,之前我们分享过1929-2024年全球气象站…...

python爬虫系列课程1:初识爬虫

python爬虫系列课程1:初识爬虫 一、爬虫的概念二、通用爬虫和自定义爬虫的区别三、开发语言四、爬虫流程一、爬虫的概念 网络爬虫(又被称为网页蜘蛛、网络机器人)就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动抓取互联网信息的程序。原则上,只要是…...

大模型工具大比拼:SGLang、Ollama、VLLM、LLaMA.cpp 如何选择?

简介:在人工智能飞速发展的今天,大模型已经成为推动技术革新的核心力量。无论是智能客服、内容创作,还是科研辅助、代码生成,大模型的身影无处不在。然而,面对市场上琳琅满目的工具,如何挑选最适合自己的那…...

什么是语料清洗、预训练、指令微调、强化学习、内容安全; 什么是megatron,deepspeed,vllm推理加速框架

什么是语料清洗、预训练、指令微调、强化学习、内容安全 目录 什么是语料清洗、预训练、指令微调、强化学习、内容安全语料清洗预训练指令微调强化学习内容安全什么是megatron,deepspeed,vllm推理加速框架语料清洗 语料清洗是对原始文本数据进行处理的过程,旨在去除数据中的…...

HTTP的“对话”逻辑:请求与响应如何构建数据桥梁?

一、前言 作为现代互联网通信的基石,HTTP协议定义了客户端与服务器之间的“对话规则”。每一次网页加载、API调用或文件传输的背后,都离不开精心构造的HTTP请求与响应。请求中封装了用户的意图——从请求方法、资源路径到提交的数据;响应则承…...

【深度学习】预训练和微调概述

预训练和微调概述 1. 预训练和微调的介绍1.1 预训练(Pretraining)1.2 微调(Fine-Tuning) 2. 预训练和微调的区别 预训练和微调是现代深度学习模型训练中的两个关键步骤,它们通常是一个 预训练-微调 (Pretrain-Finetune…...

自动化测试框架搭建-单次接口执行-三部曲

目的 判断接口返回值和提前设置的预期是否一致,从而判断本次测试是否通过 代码步骤设计 第一步:前端调用后端已经写好的POST接口,并传递参数 第二步:后端接收到参数,组装并请求指定接口,保存返回 第三…...

【阮一峰】2.数组

数组 简介 所有成员的类型必须相同,但是成员数量是不确定的。 由于成员数量可以动态变化,所以 TypeScript 不会对数组边界进行检查,越界访问数组并不会报错。 第一种写法: let arr: (number | string)[];第二种写法&#xff…...

DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方DeepSeek接入)

前言 在当今数字化时代,AI编程助手已成为提升开发效率的利器。DeepSeek作为一款强大的AI模型,凭借其出色的性能和开源免费的优势,成为许多开发者的首选。今天,就让我们一起探索如何将DeepSeek接入PyCharm,实现高效、智…...

【Java Card】Applet 使用Shareable进行数据分享以及部分问题处理

文章目录 前言一、定义接口二、server端实现三、client端实现四、遇到的问题 前言 在进行开发时,可能会将业务放到不同的applet中,这时常常会需要进行数据的分享。 比如在一个applet中存储了密钥,而在另一个业务applet中需要进行签名时&…...

国产FPGA开发板选择

FPGA开发板是学习和开发FPGA的重要工具,选择合适的开发板对学习效果和开发效率至关重要。随着国产FPGA的发展,淘宝上的许多FPGA开发板店铺也开始进行国产FPGA的设计和销售,本文将对国产FPGA和相关店铺做个简单梳理,帮助有需要使用…...

com.typesafe.config

com.typesafe.config 是 Typesafe Config 库的核心包,主要用于 统一、灵活地管理应用程序配置,支持从多种格式(如 HOCON、JSON、Java Properties)加载配置,并提供类型安全的访问接口。以下是其核心功能的详细解析&…...

Ubuntu学习备忘

1. 打开Terminal快捷键 ctrl alt t 2.Ubuntu22.04的root没有默认初始密码, 为root设置密码,下面链接的step1, How to allow GUI root login on Ubuntu 22.04 Jammy Jellyfish Linux - LinuxConfig...

【C++】— 掌握STL vector 类:“Vector简介:动态数组的高效应用”

文章目录 1.vector的介绍和使用1.1vector的介绍1.2 vector的特点1.3vector的使用1.3.1vector的定义1.3.2vector iterator的使用1.3.3vector 的空间增长问题1.3.4 vector 的增删查改1.3.5vector 迭代器失效问题 1.vector的介绍和使用 1.1vector的介绍 vector是一个顺序容器&am…...

Docker__持续更新......

Docker 1. 基本知识1.1 为什么有Docker?1.2 Docker架构与容器化 画图解释 画图解释2. 项目实战 1. 基本知识 1.1 为什么有Docker? 用一行命令跨平台安装项目,在不同平台上运行项目。把项目打包分享运行应用。 1.2 Docker架构与容器化 准备机器,在机…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

idea大量爆红问题解决

问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

在rocky linux 9.5上在线安装 docker

前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

基于服务器使用 apt 安装、配置 Nginx

🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

浅谈不同二分算法的查找情况

二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况&#xf…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...