Rust语言入门教程(七) - 所有权系统

所有权系统是Rust敢于声称自己为一门内存安全语言的底气来源,也是让Rust成为一门与众不同的语言的所在之处。也正是因为这个特别的所有权系统,才使得编译器能够提前暴露代码中的错误,并给出我们必要且精准的错误提示。

所有权系统的三个规则

  • 每个值都有一个所有者,内存中不可能存在一个没有所有者的值;
  • 一个值只有一个所有者, 没有变量可以共享一个值的所有权,其他变量可以借用这个值,但只有一个变量可以拥有它;
  • 如果某个值的所有者超出了它的作用域,这个值也会立刻从内存中被抹去;

所有权的移动

情景A

让我们用示例来说明上面的文字:

let s1 = String::from("abc");
let s2 = s1;
println!("{}", s1); // Error!

上面的例子中, 我们创建了一个字符串变量s1, 然后创建了另一个变量s2, 并将s1的值赋给它。 此时, 在Rust内存中发生的事并不是进行了一次值拷贝, 而是把s1的值移动给了s2, s1不再有值, 因为只有一个变量可以拥有该值。如果我们在进行了上面的操作之后尝试继续使用s1, 就会出现编译器错误:
请添加图片描述
让我们从内存的角度来看看上面的代码发生了什么, 首先创建一个变量s1, 上一章讲解字符串的内容中说到了, String类型的数据结构由指针,长度, 容量三部分组成,这三部分数据被压入栈中。在堆中创建了值abc, s1的指针指向堆中值所在的地址:
请添加图片描述
然后再创建s2, s2的指针, 长度, 容量都会从s1复制,并作为一个新的变量被压入栈中。请添加图片描述
如果到此为止, s1和s2的指针就都指向了同一个内存地址,这样一来,内存安全就不复存在了, 因此Rust会使s1立即失效。请添加图片描述
编译器现在会认为s1是一个已声明但是未被初始化的变量,因此是不能被使用的。如果s1被声明为一个可变的变量,理论上我们还是可以再次对它进行赋值并使用的。但是在上面的代码中,我们没有使用mut关键字声明它为可变,因此s1始终是不可变的,他的值被移动给s2后, s1就只是一个垃圾,不能再被使用了。

如果我们不想移动s1的值,而是真的想要拷贝一份呢,那可以使用clone()函数:

let s1 = String::from("abc");
let s2 = s1.clone();
println!("{}", s1); // Error!

clone()函数在内存中的行为也与值的移动不同, 不仅在栈中会复制一个变量, 在堆中也会复制一份相同的数据,并调整新变量的指针指向新复制的数据地址。
请添加图片描述
在Rust中, copy一般认为是在栈中进行的复制,clone一般认为涉及堆数据及指针更新, 在其他语言中,可以分别对应浅拷贝和深拷贝。

当变量超出作用域时,会被立即销毁,从内存堆栈的角度看,销毁意味着三件事:

  • 析构函数立即执行(如果有的话)
  • 堆中的数据被立即删除
  • 栈中的数据立即弹出

因此,不会存在内存泄漏,悬空指针这样的问题。

情景B

let s1 = String::from("abc");
do_stuff(s1);
println!("{}", s1);  // Error! s1 的值的所有权被移动到了do_stuff的局部变量s中

fn do_stuff(s: String) {
	// do stuff
}

上面的代码中,我们创建了一个String类型的变量s1, 然后创建了一个接受字符串参数但不返回任何内容的函数。如果我们将s1作为参数传递给该函数, s1的值的所有权将被移动到do_stuff函数中的局部变量s 中, 这就意味着s1将失去对其值的所有权,而不能再继续被使用了。那如果我们还想继续使用s1呢,可能会想到这样做:

let mut s1 = String::from("abc");
s1 = do_stuff(s1);
println!("{}", s1);  

fn do_stuff(s: String) -> String {
	s
}

让s1声明为一个可变变量, 让函数返回一个String类型的值,并重新赋值给s1。 看起来是解决了问题,但是总是感觉画蛇添足,怪怪的样子。跳出代码想一想这个问题, 通常,我们将变量传入函数,无非是想要使用这个值, 而其实使用这个值并不一定需要将值的所有权传递给函数,在下一章中,我们会讨论引用与借用,这将解决我们的这种需求。

小结

本章介绍了Rust的所有权系统的规则与示例,接下来会讲解Rust中的引用与借用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序生成二维码并保存到本地方法

微信小程序生成二维码请保存到本地方法 官方weapp-qrcode插件 github链接 功能完成样子 wxml <view class"qrcode"><canvas style"width: 275px; height: 275px;" canvas-idmyQrcode></canvas> </view> <view class" …

Transformers实战——文本相似度

文章目录 一、改写文本分类1.导入相关包2.加载数据集3.划分数据集4.数据集预处理5.创建模型6.创建评估函数7.创建 TrainingArguments8.创建 Trainer9.模型训练10.模型评估11.模型预测 二、交互/单塔模式1.导入相关包2.加载数据集3.划分数据集4.数据集预处理5.创建模型&#xff…

机器学习的复习笔记2-回归

一、什么是回归 机器学习中的回归是一种预测性分析任务&#xff0c;旨在找出因变量&#xff08;目标变量&#xff09;和自变量&#xff08;预测变量&#xff09;之间的关系。与分类问题不同&#xff0c;回归问题关注的是预测连续型或数值型数据&#xff0c;如温度、年龄、薪水…

springboot自定义更换启动banner动画

springboot自定义更换启动banner动画 文章目录 springboot自定义更换启动banner动画 &#x1f4d5;1.新建banner&#x1f5a5;️2.启动项目&#x1f516;3.自动生成工具&#x1f9e3;4.彩蛋 &#x1f58a;️最后总结 &#x1f4d5;1.新建banner 在resources中新建banner.txt文…

数智赋能 锦江汽车携手苏州金龙打造高质量盛会服务

作为一家老牌客运公司&#xff0c;成立于1956年的上海锦江汽车服务有限公司&#xff08;以下简称锦江汽车&#xff09;&#xff0c;拥有1200多辆大巴和5000多辆轿车&#xff0c;是上海乃至长三角地区规模最大的专业旅游客运公司。面对客运市场的持续萎缩&#xff0c;锦江汽车坚…

打破TikTok信息壁垒:东南亚达人不实名就封小黄车?跨境新店考核规则更改!

近期&#xff0c;TKFFF得到一个模糊消息&#xff0c;不保真但是个合规的趋势&#xff0c;分享给大家&#xff01; 目前泰国已落实达人实名制&#xff0c;11月底或者12月底之前可能东南亚所有达人都需要实名制&#xff0c;后期也会同步到全球。 如果达人不实名&#xff0c;会被…

蓝桥杯-平方和(599)

【题目】平方和 【通过测试】代码 import java.util.Scanner; import java.util.ArrayList; import java.util.List; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);//在此…

有哪些可信的SSL证书颁发机构?

目前市面上所显示的SSL证书颁发机构可所谓不计其数&#xff0c;类型也是多样&#xff0c;就好比我们同样是买一件T恤&#xff0c;却有百家不同类型的店铺一个道理。根据CA里面看似很多&#xff0c;但能拿到99%浏览器及设备信任度的寥寥无几&#xff0c;下面小编整理出几家靠谱可…

【substance painter】如何制作一个生锈磨损的枪

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

提升企业文档处理效率,尽在Readiris PDF Corporate下载

在现代企业中&#xff0c;大量的文档处理工作是不可避免的。然而&#xff0c;传统的文档处理方法往往效率低下&#xff0c;浪费了企业宝贵的时间和资源。为了帮助企业提升文档处理效率&#xff0c;我们推荐使用Readiris PDF Corporate软件。 Readiris PDF Corporate是一款功能…

UE4/UE5 雾

雾 UE4/UE5 雾平面雾材质效果图&#xff1a; 3D雾区材质效果图&#xff1a; UE4/UE5 雾 平面雾 做好将材质放在Plane上就行 材质 效果图&#xff1a; 3D雾区 做好将材质放在3D模型上就行 材质 效果图&#xff1a;

反转链表的三种写法

题目链接&#xff1a;https://leetcode.cn/problems/reverse-linked-list/ 方法一&#xff1a;循环&#xff0c;维护好两个节点一个前一个后 class Solution {public ListNode reverseList(ListNode head) {ListNode pre null;ListNode local head;while(local ! null){List…

信奥编程 1168:大整数加法

解析&#xff1a;在c中需要考虑这么几个问题&#xff0c;第一个是大数据的输入&#xff0c;第二个是大数据的存储&#xff0c;第三是大数据的计算方式&#xff0c;最后是输出。 针对上述几个问题&#xff0c;第一个问题&#xff0c;采用字符串的方式或者数组加循环的方式接收输…

Typora+PicGo+Minio搭建博客图床

文章目录 TyporaPicGoMinio搭建博客图床前言什么是图床?为什么需要图床?准备工作一、Typora二、Picgo1. 下载Picgo2. 下载node.js3. 下载minio插件 三、服务器端配置1. 添加端口到安全组2. 使用Docker安装minio3. 配置minio image-20231127175530696四、minio插件配置五、Typ…

c++_继承

&#x1f3f7;如被何实现一个不能被继承的类&#xff08;或是继承无意义的类&#xff09; 将构造函数定义成私有的就行了&#xff0c;即&#xff1a;私有化父类的构造函数 c 11 新增关键字final 修饰父类直接不能被继承 class A final {........ }&#x1f3f7;继承与有元 有…

Vue CLI 初体验之如何创建一个项目并打开,以及组件的简单使用案例。

目录 什么是Vue CLI? 如何使用Vue CLI 创建一个项目 1.winr 打开cmd 输入vue create 1127(1127是文件名) 2.配置基础设置 选择Manually select features 选择Router和Vuex 选中vue版本&#xff08;我这里选vue3&#xff09; 剩下的看自己需要&#xff0c;如果不确定就一…

zabbix 6.0 原理与部署

一、zabbix简介&#xff1a; zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 zabbix 能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 zabbi…

如何迁移数据到水经微图64位版?

我们在《为什么要升级水经微图到64位&#xff1f;》一文中&#xff0c;为大家分享了升级水经微图到64位的原因。 这里&#xff0c;我们再为大家分享一下在哪些情况下升级需要迁移已标注的数据&#xff0c;以及如何迁移已标注绘制的数据到水经微图64位中。 哪些情况需要迁移数…

Vue路由跳转页面刷新

案例使用映射路由 百度的时候各种操作就是没有注意keepAlive&#xff0c;发现那个为缓存开启之后前端有个小后台Vue生命周期函数失效。同一个页面刷新时这个keep Alive需要关闭。

11 OAuth2.0实战:网关统一认证授权

上一节介绍了认证中心,这节介绍下网关如何集成认证中心实现网关的统一认证授权。 木谷博客系统的整个认证授权架构设计如下图: 网关在这里的主要功能就是6-8这三步: 校验token:对令牌的过期时间、签名进行校验鉴权:对令牌的权限进行校验转发:解析令牌中的相关信息,通过…