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中的引用与借用。

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

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

相关文章

Anaconda安装教程(超详细版)

目录 一、Anaconda简介 二、运行环境 三、安装Anaconda 四、手动配置环境变量(重点) 五、测试Anaconda环境是否配置成功 一、Anaconda简介 Anaconda,一个开源的Python发行版本,可用于管理Python及其相关包,包含了…

慕尼黑电子展采访全程 | Samtec管理层对话电子发烧友:虎家卓越服务

【摘要/前言】 今年的慕尼黑上海电子展上,Samtec大放异彩,特装展台一亮相就获得了大家的广泛关注,展台观众络绎不绝。 作为深耕连接器行业数十年的知名厂商以及Electronica的常客,Samtec毫无疑问地获得了大量媒体朋友的关注和报…

【数据结构】二叉树之链式结构

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一、前置说明二、二叉树的遍历2.1 前序遍历2.2 中序遍历2.3 后序遍历2.4 层序遍历 三、…

如何在本地安装部署WinSCP,并实现公网远程本地服务器

可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器 文章目录 可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器1. 简介2. 软件下载安装:3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 …

送PDF书 | 豆瓣9.2分,超250万Python新手的选择!蟒蛇书入门到实践

在此疾速成长的科技元年,编程就像是许多人通往无限可能世界的门票。而在编程语言的明星阵容中,Python就像是那位独领风 骚的超级巨星, 以其简洁易懂的语法和强大的功能,脱颖而出,成为全球最炙手可热的编程语言之一。 …

Gitea和Jenkins安装

Gitea Gitea:https://dl.gitea.com/gitea/1.21.0/ Jenkins:https://www.jenkins.io/download/ 数据库配置 可以参考官方文档-https://docs.gitea.cn/1.20/installation/database-prep,这里以MySQL作为讲解 MySQL 在数据库实例上&#xf…

智能物流时代:快递物流信息订阅与推送API自动推送物流变更信息

引言 在当今数字化和智能化的时代,物流行业也在迅速演变,通过技术创新提高效率、提升服务质量。其中,快递物流信息订阅与推送API的自动推送功能成为推动物流领域发展的重要驱动力。本文将深入探讨这一趋势,并分析快递物流信息订阅…

完美解决:vue.js:6 TypeError: Cannot read properties of undefined (reading ‘0‘)

Vue项目出现以下报错: 原因: 在渲染的时候,不满足某个条件而报错,或者某个属性丢失或后台没传过来导致 我这里出现的原因是后台给我传递过来的数组中,其中有一条少传了一个我在渲染时需要用的属性,没让后台…

如何使用Java支付宝沙箱环境并公网调用sdk创建支付单服

Java支付宝沙箱环境支付,SDK接口远程调试【内网穿透】 1.测试环境 MavenSpring bootJdk 1.8 2.本地配置 获取支付宝支付Java SDK,maven项目可以选择maven版本,普通java项目可以在GitHub下载,这里以maven为例 SDK下载地址:https://doc.open.alipay.com…

阻塞队列及简单实现,生产者消费者模型

文章目录 阻塞队列阻塞队列是什么生产者消费者模型阻塞队列的实现 阻塞队列 阻塞队列是什么 阻塞队列是一种特殊的队列. 也遵守 “先进先出” 的原则. 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素当队列空的时候, 继续出队列也会阻塞, 直到有其他线…

有效实施的五条教学策略

作为老师,是否曾为如何提高教学质量而苦恼?也为如何引导学生而思考?如果你正面临这些困扰,那么这篇文章将对你有帮助。为你介绍五条教学策略,帮你实施教学,提高效果。 明确教学目标 你是否知道你的教学目标…

针对操作系统漏洞的反馈方法

一、针对操作系统漏洞的反馈方法 漏洞扫描指基于漏洞数据库,通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测,发现可利用漏洞的一种安全检测(渗透攻击)行为。在进行漏洞扫描后,需先确定哪些是业务…

Go 内置运算符

一、算数运算符 1、算数运算符使用 package mainimport ("fmt" )func main(){fmt.PrintIn("103",103) //10313fmt.PrintIn("10-3",10-3) //10-37fmt.PrintIn("10*3",10*3) //10*330//除法注意:如果运算的数都是…

视频后期效果制作工具Mocha Pro 2022 Plugins mac中文版软件介绍

Mocha Pro 2022 mac是一款专业的三维摄像机反求摩卡跟踪插件,同时也是一款视频后期效果制作工具,Mocha Pro 2022下载能够给数字媒体艺术家提供强大的、直观的和创新的追踪解决方案用简化的界面、加速的工作流程以及轻松追踪和操作镜头的强大性&#xff0…

js moment时间范围拿到中间间隔时间

2023.11.27今天我学习了如何对只返回的开始时间和结束时间做处理,比如后端返回了: [time:{start:202301,end:202310}] 我们需要把中间的间隔渲染出来。 [202301,202302,202303,202304,202305,202306,202307,202308,202309,202310] 利用moment的add进…

Linux下使用Docker部署MinIO存储服务实现远程上传

📑前言 本文主要是Linux下通过Docker部署MinIO存储服务实现远程上传的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 &#…

【AD9371 AD9375 概要总结】A ...

目录 工作原理发射器 TRANSMITTER(Tx)接收器 RECEIVER (Rx)观测接收器 OBSERVATION RECEIVER (ORx)嗅探接收器 SNIFFER RECEIVER(SnRx)时钟输入 CLOCK INPUTSYNTHESIZERS合成RF PLL射…

推动企业数字化转型,如何更好地规避失败风险?

随着科技的飞速发展,数字化转型已成为企业持续发展的必然选择,然而有相关数据显示,超过80%的企业在数字化转型过程中都遭遇失败。本文将揭示企业数字化转型常见的失败原因,并探讨如何帮助企业规避转型失败风险。 一、企业数字化转…

力扣:182. 查找重复的电子邮箱(Python3)

题目: 表: Person ---------------------- | Column Name | Type | ---------------------- | id | int | | email | varchar | ---------------------- id 是该表的主键(具有唯一值的列)。 此表的每一行都包含一封电子…

飞翔的鸟小游戏

第一步是创建项目 项目名自拟 第二步创建个包名 来规范class 再创建一个包 来存储照片package game; import java.awt.*; import javax.swing.*; import javax.imageio.ImageIO; public class Bird { Image image; int x,y; int width,height; int size…