Rust - 变量与数据的交互方式(move)

news2024/12/27 13:59:24

变量与数据的交互方式 - 移动

Rust 中的多个变量可以采用一种比较独特的方式和同一个数据进行交互,如下代码所示,将变量x的值赋给y

fn main() {
    let x = 1;
    let y = x;
}

我们大概可以推论出上述代码的原理:将1这个整数绑定给x变量,let y = x相当于创建了一个x的副本,并且将这个副本绑定给了y。现在有了两个变量,x和 y,都等于 1。这也正是事实上发生了的,因为整数是有已知固定大小的简单值,所以这两个 1被放入了栈中。

上面是已知固定大小的简单例子,现在看一下复杂的例子就是String

fn main() {
    let str1 = String::from("hello");
    let str2 = str1;
}
复制代码

上述代码看起来和整数的例子非常相似,所以我们可能会假设他们的运行方式也是类似的:也就是说,第二行可能会生成一个 str1的副本并绑定到 str2上。不过,事实上并不完全是这样。

首先我们需要知道String底层是什么样的,String在内存中由三部分组成,如下如所示,是将值hello绑定给str1String在内存中的表现形式。一个指向存放字符串内容内存的指针,一个长度,和一个容量。这一组数据存储在栈上。右侧则是堆上存放内容的内存部分。

图1

长度表示 String的内容当前使用了多少字节的内存。容量是 String从操作系统总共获取了多少字节的内存。长度与容量的区别是很重要的,不过在当前上下文中并不重要,所以现在可以忽略容量。

当我们将 str1赋值给 str2String的数据被复制了,这意味着我们从栈上拷贝了它的指针、长度和容量。我们并没有复制指针指向的堆上数据。换句话说,内存中数据的表现如下图所示。

图2

这个表现形式看起来 并不像下图 中的那样,如果 Rust 也拷贝了堆上的数据,那么内存看起来就是这样的。如果 Rust 这么做了,那么操作 str2 = str1在堆上数据比较大的时候会对运行时性能造成非常大的影响。

图3

之前我们提到过当变量离开作用域后,Rust 自动调用 drop函数并清理变量的堆内存。不过图 2 展示了两个数据指针指向了同一位置。这就有了一个问题:当 str2和 str1离开作用域,他们都会尝试释放相同的内存。这是一个叫做 二次释放double free)的错误,也是之前提到过的内存安全性 bug 之一。两次释放(相同)内存会导致内存污染,它可能会导致潜在的安全漏洞。

为了确保内存安全,这种场景下 Rust 有另一个独到的处理。与其尝试拷贝被分配的内存,Rust 则认为 str1不再有效,因此 Rust 不需要在 str1离开作用域后清理任何东西。看看在 str2被创建之后尝试使用 str1会发生什么:

fn main() {
    let s1 = String::from("hello");
	let s2 = s1;

	println!("{}, world!", s1);
}

运行cargo run就会报错,因为Rust禁止使用无效的引用:

error[E0382]: use of moved value: `s1`
 --> src/main.rs:5:28
  |
3 |     let s2 = s1;
  |         -- value moved here
4 |
5 |     println!("{}, world!", s1);
  |                            ^^ value used here after move
  |
  = note: move occurs because `s1` has type `std::string::String`, which does
  not implement the `Copy` trait

如果你在其他语言中听说过术语 浅拷贝shallow copy)和 深拷贝deep copy),那么拷贝指针、长度和容量而不拷贝数据可能听起来像浅拷贝。不过因为 Rust 同时使第一个变量无效了,这个操作被称为 移动move),而不是浅拷贝。上面的例子可以解读为 s1被 移动到了 s2中。那么具体发生了什么,如下图 所示。

这就解决了二次释放的错误,因为只有 s2是有效的,当其离开作用域,它就释放自己的内存,完毕。

另外,这里还隐含了一个设计选择:Rust 永远也不会自动创建数据的 “深拷贝”。因此,任何 自动的复制可以被认为对运行时性能影响较小。

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

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

相关文章

Mybatis读取和存储json类型的数据

目录 一、测试使用JSONObject来获取json二、设置TableName的autoResultMap为true,TableField的typeHandler为JacksonTypeHandler.class三、设置xml当中的resultMap四、JacksonTypeHandler讲解五、新增假如是JSONObject 不管数据库当中是以json还是longtext数据类型来…

树莓派Opencv调用摄像头(Raspberry Pi 11)

前言:本人初玩树莓派opencv,使用的是树莓派Raspberry Pi OS 11,系统若不一致请慎用,本文主要记录在树莓派上通过Opencv打开摄像头的经验。 1、系统版本 进入树莓派,打开终端输入以下代码(查看系统的版本&…

“人工智能教父”从谷歌离职 称后悔发展AI,为世人敲响警钟?

在加入谷歌的第十年、深度学习迎来爆发式发展的当下,被誉为“人工智能教父”的Geoffrey Hinton已从谷歌离职,只是为了告诫人们AI已经变得很危险。 公开资料显示,Geoffrey Hinton在2013年加入谷歌,曾任副总裁,研究机器学…

Python每日一练:硬币的面值奇偶排序陶陶摘苹果(花样解法)

Python每日一练 文章目录 Python每日一练前言一、硬币的面值二、奇偶排序三、陶陶摘苹果总结 前言 很显然,Python的受众远远大于C,其实笔者本人对Python的理解也是远强于C的,C纯粹是为了假装笔者是个职业选手才随便玩玩的,借着十…

【是C++,不是C艹】 缺省参数 | 函数重载 | 内联函数

💞💞欢迎来到 Claffic 的博客 💞💞 👉 专栏:《是C,不是C艹》👈 前言: 上期,我带大家给C打了招呼,捎带着认识了命名空间和输入输出,那…

SPSS如何使用基础功能?

文章目录 0.引言1.菜单栏2.工具栏 0.引言 因科研等多场景需要进行绘图处理,笔者对SPSS进行了学习,本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结,本文对软件界面基础功能进行阐述。    1.菜单栏 &am…

如何向面试官正确地提问?

你好,我是朱显杰。今天我们来聊一聊面试时,如何向面试官正确提问。 我做过8年面试官,面试过500多人。在面试的过程中,我发现了一个普遍现象,就是大部分候选人都不知道如何向面试官正确提问。要么不问,白白…

RocketMq源码分析(六)--消息消费者启动流程

文章目录 一、消息消费者模式二、消费者启动流程1、 push模式1)类关系2)类构造器3)启动流程 2、pull模式1)类关系2)类构造器3)启动流程 一、消息消费者模式 消息消费分两种模式:推(p…

【Redis】Redis缓存双写一致性之更新策略

介绍 面试题 1、只要用到缓存,就可能会涉及到Redis缓存与数据库双存储双写,只要是双写,就一定会有数据一致性问题,怎么解决一致性问题? 2、双写一致性,先动缓存redis还是数据库mysql?为什么&a…

剪枝与重参第十课:RepVGG重参

目录 RepVGG重参前言1. RepVGG2. RepVGG网络搭建2.1 conv_bn2.2 RepVGG Block初始化2.3 forward2.4 branch的合并2.5 重参的实现2.6 整体网络结构搭建2.7 模型导出 3. 完整示例代码总结 RepVGG重参 前言 手写AI推出的全新模型剪枝与重参课程。记录下个人学习笔记,仅…

了解npm run指令

了解npm run指令 在package.json文件中的script字段,可以定义脚本命令,通过npm run指令运行该脚本。 比如简单定义一个输出打印的shell脚本。 {"script": {"hw": "echo hello world!"} }执行npm run hw可以看到终端上打…

Python---正则表达式与递归

1. 正则表达式: 是一种字符串验证的规则,通过特殊的字符串组合来确立规则 用规则去匹配字符串是否满足 如(^[\w-](\.[\w-])*[\w-](\.[\w-])$)可以表示为一个标准邮箱的格式 re模块的三个主要方法: re.match: re.match(匹配规…

电子电气架构——车辆E/E架构Software独立性

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人只有在举棋不定,无从把握的时候才感到疲惫。只有去行动就能获得解放,哪怕做的不好也比无所作为强! 本文主要介绍车辆E/E架构常识,主要涉及E/E架构车载…

Java 操作ElasticSearch

Java REST提供了两种风格的客户端连接工具,Java High Level REST Client、Java Low Level REST Client,这里我就不去细说Java Low Level REST Client了,因为这我确实没用到过,也不是很了解,我说一下Java High Level RE…

LVS 负载均衡群集的 NAT 模式和 DR 模式

文章目录 一、NAT 模式和 DR 模式的介绍DR模式NAT模式两种模式的区别 二、DR模式集群构建配置 一、NAT 模式和 DR 模式的介绍 DR模式 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间PREROUTING链首先会接收到…

【JavaEE】HTML基础知识

目录 1.HTML结构 2.HTML常见标签 3.表格标签 4.列表标签 5.表单标签 ​6.select 标签 7.textarea 标签 8.无语义标签: div & span 9.标签小练习 1.HTML结构 形如&#xff1a; <body idmyId>hello</body> HTML的书写格式 标签名 (body) 放到 <…

【操作系统OS】学习笔记:第二章 进程与线程 (上)【哈工大李治军老师】

基于本人观看学习 哈工大李治军老师主讲的操作系统课程 所做的笔记&#xff0c;仅进行交流分享 特此鸣谢李治军老师&#xff0c;操作系统的神作&#xff01; 如果本篇笔记帮助到了你&#xff0c;还请点赞 关注 支持一下 ♡>&#x16966;<)!! 主页专栏有更多&#xff0c;…

58.网页设计规则#5_阴影

一些概念 ● 在一个100%平面设计的时代之后&#xff0c;我们现在又回到了在UI设计中使用阴影(“平面设计2.0”) ● 阴影箱深度(3D):阴影越多&#xff0c;离元素界面越远 利用好阴影 你不必使用阴影!只在对网站个性有意义的情况下使用它们 使用少量的阴影:不要给每个元素…

Jmeter接口自动化测试系列之Http接口自动化实战

以下主要介绍Jmeter接口自动化需要哪些控件、接口自动化实战及总结。 前面的系列文章&#xff0c;介绍了常用组件、参数化、接口依赖、断言等知识点&#xff0c;今天我们要将这些结合起来&#xff0c;进行综合实战。 2023年B站最新Jmeter接口测试实战教程&#xff0c;精通接口…

从一到无穷大 #5 公有云时序数据库定价

文章目录 引言serverless实例售卖结论 Azure CosmosDB预配吞吐量自动缩放吞吐量Serverless预留容量存储量 Amazon Timestream写入计费查询计费存储 阿里云TSDB阿里云Lindom时序引擎实例固定费用存储费用节点费用 华为云GaussDB(for Influx)腾讯云CTSDBTDengineInfluxDB CloudAW…