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中的引用与借用。
相关文章:

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

【MATLAB源码-第89期】基于matlab的灰狼优化算法(GWO)无人机三维路径规划,输出做短路径图和适应度曲线
操作环境: MATLAB 2022a 1、算法描述 灰狼优化算法(Grey Wolf Optimizer, GWO)是一种模仿灰狼捕食行为的优化算法。灰狼是群居动物,有着严格的社会等级结构。在灰狼群体中,通常有三个等级:首领ÿ…...
线程池的饱和策略有哪些?
线程池的饱和策略是指当线程池中的任务队列已满时,线程池如何处理新提交的任务。常见的饱和策略有以下几种: 阻塞策略 阻塞策略是指当线程池中的任务队列已满时,新提交的任务会等待队列中有空闲位置后再执行。这种策略可以避免过多的任务被…...
Git设置多个仓库同时推送
Git设置多个仓库同时推送 添加 在Git中,有时我们需要将同一份代码推送到不同的远程仓库,只是URL地址不同。 下面是一种优化的方法来设置多个仓库同时推送: # 添加一个新的远程仓库 git remote set-url --add origin2 新的仓库地址这样&am…...

前端入职环境安装
前端入职 后环境安装 ,内函 nodenvmgit微信开发者工具vscode 的安装包 一.node安装-js运行环境 1.node下载,下载地址Node.js 2.配置淘宝镜像 npm config set registry https://registry.npmmirror.com/ 3.查看配置 npm config list 二.nvm安装-切…...

《金融科技行业2023年专利分析白皮书》发布——科技变革金融,专利助力行业发展
金融是国民经济的血脉,是国家核心竞争力的重要组成部分,金融高质量发展成为2023年中央金融工作的重要议题。《中国金融科技调查报告》中指出,我国金融服务业在科技的助力下,从1.0时代的“信息科技金融”、2.0时代的“互联网金融”…...
Introducing the Arm architecture
快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 — 适合小白入门【目录】ARMv8/ARMv9架构高级进阶-[目录]👈👈👈 — 高级进阶、小白勿买【加群】ARM/TEE…...
Python 使用SQLAlchemy数据库模块
SQLAlchemy 是用Python编程语言开发的一个开源项目,它提供了SQL工具包和ORM对象关系映射工具,使用MIT许可证发行,SQLAlchemy 提供高效和高性能的数据库访问,实现了完整的企业级持久模型。 ORM(对象关系映射࿰…...
【nlp】4.3 nlp中常用的预训练模型(BERT及其变体)
nlp中常用的预训练模型 1 当下NLP中流行的预训练模型1.1 BERT及其变体1.2 GPT1.3 GPT-2及其变体1.4 Transformer-XL1.5 XLNet及其变体1.6 XLM1.7 RoBERTa及其变体1.8 DistilBERT及其变体1.9 ALBERT1.10 T5及其变体1.11 XLM-RoBERTa及其变体2 预训练模型说明3 预训练模型的分类1…...

IDEA中 java: 警告: 源发行版 11 需要目标发行版 11 如何解决
步骤1找到项目结构,下面有两种方式 步骤2找到 模块中对应的项目,修改对应的源的语言级别和依赖的模块SDK(M) 步骤3,启动一下,看有无问题, 步骤4,去文件-->设置-->构建、执行、部署-->编译器-->…...

APP测试的测试内容有哪些,常见的Bug分类介绍!
对于产品的手机项目(应用软件),主要是进行系统测试。而针对手机应用软件APP的系统测试,我们通常从如下几个角度开展:功能模块测试、兼容性测试、安装和卸载测试、软件更新测试、性能测试、用户体验性测试、交叉事件测试…...

【Java程序员面试专栏 专业技能篇】Java SE核心面试指引(三):核心机制策略
关于Java SE部分的核心知识进行一网打尽,包括四部分:基础知识考察、面向对象思想、核心机制策略、Java新特性,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第三部分:核心机制策略,子节点表示追问或同级提问 异常处理 …...

网络运维与网络安全 学习笔记2023.11.22
网络运维与网络安全 学习笔记 第二十三天 今日目标 VLAN间通信之交换机、VLAN间通信综合案例、浮动路由 VRRP原理与配置、VRRP链路跟踪、VRRP安全认证 VLAN间通信之交换机 单臂路由的缺陷 在内网的VLAN数量增多时,单臂链路容易成为网络瓶颈 三层交换机 具备…...
Android虚拟化
一、开源项目 开源的项目有一些,比如完全虚拟化的: twoyi 两仪由两部分组成:两仪 App,它实际上是一个 UI 渲染引擎,两仪内部运行的 ROM。 但是看telegram和github,这个app没有完整开源,并且最近…...
Nginx如何配置负载均衡
nginx的负载均衡有4种模式: 1)、轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 2)、weight 指定轮询几率,weight和访问比率成正比,用于后端服务…...
Python虚拟环境
Python虚拟环境 介绍 虚拟环境(virtual environment),它是一个虚拟化,从电脑独立开辟出来的环境。通俗的来讲,虚拟环境就是借助虚拟机来把一部分内容独立出来,我们把这部分独立出来的东西称作“容器”&am…...

单片机学习4——中断的概念
中断的概念: CPU在处理A事件的时候,发生了B事件,请求CPU迅速去处理。(中断产生) CPU暂时中断当前的工作,转去处理B事件。(中断响应和中断服务) 待CPU将B事件处理完毕后࿰…...

Go语言网络爬虫工程经验分享:pholcus库演示抓取头条新闻的实例
网络爬虫是一种自动从互联网上获取数据的程序,它可以用于各种目的,如数据分析、信息检索、竞争情报等。网络爬虫的实现方式有很多,不同的编程语言和框架都有各自的优势和特点。在本文中,我将介绍一种使用Go语言和pholcus库的网络爬…...

Git安装
简单粗暴,跟着步骤一步一步来 右键就会有了...

以太网通讯协议小结--持续更新中
一、以太网介绍 以太网是一种产生较早,使用相当广泛的局域网技术,局域网就是一个区域的网络互联,可以使办公室也可以是学校等等,大小规模不一。 目前以太网根据速度等级分类大概分为:标准以太网(10Mbit/s…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...