rust学习——栈、堆、所有权

文章目录

  • 栈、堆、所有权
    • 栈(Stack)与堆(Heap)
      • 性能区别
      • 所有权与堆栈
  • 所有权原则
    • 变量作用域
    • 所有权与函数
    • 返回值与作用域

栈、堆、所有权

栈(Stack)与堆(Heap)

栈和堆是编程语言最核心的数据结构,但是在很多语言中,你并不需要深入了解栈与堆。 但对于 Rust 这样的系统编程语言,值是位于栈上还是堆上非常重要, 因为这会影响程序的行为和性能。

栈和堆的核心目标就是为程序在运行时提供可供使用的内存空间。

栈按照顺序存储值并以相反顺序取出值,这也被称作后进先出。想象一下一叠盘子:当增加更多盘子时,把它们放在盘子堆的顶部,当需要盘子时,再从顶部拿走。不能从中间也不能从底部增加或拿走盘子!

增加数据叫做进栈,移出数据则叫做出栈

因为上述的实现方式,栈中的所有数据都必须占用已知且固定大小的内存空间,假设数据大小是未知的,那么在取出数据时,你将无法取到你想要的数据。

与栈不同,对于大小未知或者可能变化的数据,我们需要将它存储在堆上。

当向堆上放入数据时,需要请求一定大小的内存空间。操作系统在堆的某处找到一块足够大的空位,把它标记为已使用,并返回一个表示该位置地址的指针, 该过程被称为在堆上分配内存,有时简称为 “分配”(allocating)。

接着,该指针会被推入中,因为指针的大小是已知且固定的,在后续使用过程中,你将通过栈中的指针,来获取数据在堆上的实际内存位置,进而访问该数据。

由上可知,堆是一种缺乏组织的数据结构。想象一下去餐馆就座吃饭: 进入餐馆,告知服务员有几个人,然后服务员找到一个够大的空桌子(堆上分配的内存空间)并领你们过去。如果有人来迟了,他们也可以通过桌号(栈上的指针)来找到你们坐在哪。

性能区别

写入方面:入栈比在堆上分配内存要快,因为入栈时操作系统无需分配新的空间,只需要将新数据放入栈顶即可。相比之下,在堆上分配内存则需要更多的工作,这是因为操作系统必须首先找到一块足够存放数据的内存空间,接着做一些记录为下一次分配做准备。

读取方面:得益于 CPU 高速缓存,使得处理器可以减少对内存的访问,高速缓存和内存的访问速度差异在 10 倍以上!栈数据往往可以直接存储在 CPU 高速缓存中,而堆数据只能存储在内存中。访问堆上的数据比访问栈上的数据慢,因为必须先访问栈再通过栈上的指针来访问内存。

因此,处理器处理分配在栈上数据会比在堆上的数据更加高效。

所有权与堆栈

当你的代码调用一个函数时,传递给函数的参数(包括可能指向堆上数据的指针和函数的局部变量)依次被压入栈中,当函数调用结束时,这些值将被从栈中按照相反的顺序依次移除。

因为堆上的数据缺乏组织,因此跟踪这些数据何时分配和释放是非常重要的,否则堆上的数据将产生内存泄漏 —— 这些数据将永远无法被回收。这就是 Rust 所有权系统为我们提供的强大保障。

对于其他很多编程语言,你确实无需理解堆栈的原理,但是在 Rust 中,明白堆栈的原理,对于我们理解所有权的工作原理会有很大的帮助


所有权原则

理解了堆栈,接下来看一下关于所有权的规则,首先请谨记以下规则:

1. Rust 中每一个值都被一个变量所拥有,该变量被称为值的所有者

2. 一个值同时只能被一个变量所拥有,或者说一个值只能拥有一个所有者

3. 当所有者(变量)离开作用域范围时,这个值将被丢弃(drop)

变量作用域

作用域是一个变量在程序中有效的范围, 假如有这样一个变量:

let s = "hello";

变量 s 绑定到了一个字符串字面值,该字符串字面值是硬编码到程序代码中的。s 变量从声明的点开始直到当前作用域的结束都是有效的:

{                      // s 在这里无效,它尚未声明let s = "hello";   // 从此处起,s 是有效的// 使用 s
}                      // 此作用域已结束,s不再有效

简而言之,s 从创建伊始就开始有效,然后有效期持续到它离开作用域为止,可以看出,就作用域来说,Rust 语言跟其他编程语言没有区别。

所有权与函数

将值传递给函数在语义上与给变量赋值相似。向函数传递值可能会移动或者复制,就像赋值语句一样。以下示例使用注释展示变量何时进入和离开作用域:
在这里插入图片描述
代码

fn main() {let s = String::from("hello");  // s 进入作用域takes_ownership(s);             // s 的值移动到函数里 ...// ... 所以到这里不再有效let x = 5;                      // x 进入作用域makes_copy(x);                  // x 应该移动函数里,// 但 i32 是 Copy 的,所以在后面可继续使用 x} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值已被移走,// 所以不会有特殊操作fn takes_ownership(some_string: String) { // some_string 进入作用域println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放fn makes_copy(some_integer: i32) { // some_integer 进入作用域println!("{}", some_integer);
} // 这里,some_integer 移出作用域。不会有特殊操作

返回值与作用域

返回值也可以转移所有权。以下示例 一样带有类似的注释。
在这里插入图片描述
运行结果
返回unused警告
在这里插入图片描述

代码

fn main() {let s1 = gives_ownership();         // gives_ownership 将返回值// 移给 s1let s2 = String::from("hello");     // s2 进入作用域let s3 = takes_and_gives_back(s2);  // s2 被移动到// takes_and_gives_back 中,// 它也将返回值移给 s3
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,// 所以什么也不会发生。s1 移出作用域并被丢弃fn gives_ownership() -> String {           // gives_ownership 将返回值移动给// 调用它的函数let some_string = String::from("yours"); // some_string 进入作用域some_string                              // 返回 some_string 并移出给调用的函数
}// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域a_string  // 返回 a_string 并移出给调用的函数
}

变量的所有权总是遵循相同的模式:将值赋给另一个变量时移动它。当持有堆中数据值的变量离开作用域时,其值将通过 drop 被清理掉,除非数据被移动为另一个变量所有。

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

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

相关文章

ReentrantLock与synchronized区别之比较(面试)

背景: 我们Java开发中需要保证数据线程安全时有多重选择,直接使用线程安全的集合类,或者某些变量我们通过ReentrantLock来保证安全,或者使用synchronized关键字,那两者有何区别? 备注: Reent…

Linux编程——多任务间通信和同步

在前面的文章中(Linux编程基础——多线程),简单对Linux中的多线程进行了介绍,包括pthread、信号量与互斥锁,本文将对Linux编程中的多任务间通信与同步技术进行相对完整的补充。 在Linux中有两种多任务实现手段&#xf…

ubuntu20.04安装MySQL8、MySQL服务管理、mysql8卸载

ubuntu20.04安装MySQL8 #更新源 sudo apt-get update #安装 sudo apt-get install mysql-serverMySQL服务管理 # 查看服务状态 sudo service mysql status # 启动服务 sudo service mysql start # 停止服务 sudo service mysql stop # 重启服务 sudo service mysql restart登…

中间件安全-CVE复现WeblogicJenkinsGlassFish漏洞复现

目录 服务攻防-中间件安全&CVE复现&Weblogic&Jenkins&GlassFish漏洞复现中间件-Weblogic安全问题漏洞复现CVE_2017_3506漏洞复现 中间件-JBoos安全问题漏洞复现CVE-2017-12149漏洞复现CVE-2017-7504漏洞复现 中间件-Jenkins安全问题漏洞复现CVE-2017-1000353漏…

idea设置字体大小快捷键 Ctrl+鼠标上下滑 字体快捷键缩放设置

双击 按住ctrl鼠标滑轮上划放大就好了 这个双击设置为,Ctrl鼠标下滑 字体缩小就好了

03-垃圾收集策略与算法

垃圾收集策略与算法 程序计数器、虚拟机栈、本地方法栈随线程而生,也随线程而灭;栈帧随着方法的开始而入栈,随着方法的结束而出栈。这几个区域的内存分配和回收都具有确定性,在这几个区域内不需要过多考虑回收的问题,因…

手把手创建属于自己的ASP.NET Croe Web API项目

第一步:创建项目的时候选择ASP.NET Croe Web API 点击下一步,然后配置: 下一步:

Adobe Photoshop 基本操作

PS快捷键 图层 选择图层 Ctrl T:可以对图层的大小和位置进行调整 填充图层 MAC: AltBackspace (前景) or CtrlBackspace (背景) WINDOWS: AltDelete (前景) or CtrlDelete (背景) 快速将图层填充为前景色或背景色 平面化图层(盖印图层&#xff09…

性能测试LoadRunner02

本篇主要讲:通过Controller设计简单的测试场景,可以简单的分析性能测试报告。 Controller 设计场景 Controller打开方式 1)通过VUG打开 2)之间双击Controller 不演示了,双击打开,选择Manual Scenario自…

《视觉 SLAM 十四讲》V2 第 9 讲 后端优化1 【扩展卡尔曼滤波器 EKF BA+非线性优化(Ceres、g2o)】

文章目录 第9讲 后端19.1.2 线性系统和 KF9.1.4 扩展卡尔曼滤波器 EKF 不足 9.2 BA 与 图优化9.2.1 投影模型和 BA 代价函数9.2.2 BA 的求解9.2.3 稀疏性 和 边缘化9.2.4 鲁棒核函数 9.3 实践: Ceres BA 【Code】本讲 CMakeLists.txt 9.4 实践:g2o 求解 …

100 # mongoose 的使用

mongoose elegant mongodb object modeling for node.js https://mongoosejs.com/ 安装 mongoose npm i mongoose基本示例 const mongoose require("mongoose");// 1、连接 mongodb let conn mongoose.createConnection("mongodb://kaimo313:kaimo313loc…

如何从小白成长为AI工程师笔记

📚入门机器学习基础 对于本科生来说,需要打好数学基础,包括高数、概率论和线性代数。 对于已经上研究生或工作想转行的人来说,可以直接开始学习机器学习算法,重要的是理解算法的原理和推导过程。如果有时间和需要&am…

Roslyn 去除多余using

原因 当你添加新代码的时候VS会自动帮你添加对应的using,但是它只会帮你加不会帮你减 由于运行时并不能使用UnityEditor命名空间里面的东西。你就算加了也会在打包的时候给你报错,除非使用宏包裹起来 因为我们打包都是在打包机上操作的。一般情况下自己…

vue3 拖拽插件 Vue3DraggableResizable

Vue3DraggableResizable 拖拽插件的官方文档 一、Vue3DraggableResizable 的属性和事件 1、Vue3DraggableResizable 的属性配置 属性类型默认值功能描述示例initWNumbernull设置初始宽度&#xff08;px&#xff09;<Vue3DraggableResizable :initW“100” />initHNumb…

sql高级教程-索引

文章目录 架构简介1.连接层2.服务层3.引擎层4.存储层 索引优化背景目的劣势分类基本语法索引结构和适用场景 性能分析MySq| Query Optimizerexplain 索引优化单表优化两表优化三表优化 索引失效原因 架构简介 1.连接层 最上层是一些客户端和连接服务&#xff0c;包含本地sock通…

1 Go的前世今生

概述 Go语言正式发布于2009年11月&#xff0c;由Google主导开发。它是一种针对多处理器系统应用程序的编程语言&#xff0c;被设计成一种系统级语言&#xff0c;具有非常强大和有用的特性。Go语言的程序速度可以与C、C相媲美&#xff0c;同时更加安全&#xff0c;支持并行进程。…

[架构之路-241]:目标系统 - 纵向分层 - 企业信息化与企业信息系统(多台企业应用单机组成的企业信息网络)

目录 前言&#xff1a; 一、什么是信息系统&#xff1a;计算机软件硬件系统 1.1 什么是信息 1.2 什么是信息系统 1.3 什么是信息技术 1.4 什么是信息化与信息化转型 1.5 什么是数字化与数字化转型&#xff08;信息化的前提&#xff09; 1.6 数字化与信息化的比较 1.7 …

力扣每日一题58:最后一个单词的长度

题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello World&q…

Arduino IDE + Esp32 Cam + 实现视频流 + 开发环境部署

1、开发环境 Arduino ide 版本&#xff1a;2.2.1 esp32工具&#xff1a;2.0.5 示例代码 #include "esp_camera.h" #include <WiFi.h>// // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality // Ensure ESP32 Wrover Modu…

Zookeeper、Kafka集群与Filebeat+Kafka+ELK架构、部署实例

Zookeeper、Kafka集群与FilebeatKafkaELK架构、部署实例 一、Zookeeper1.1、Zookeeper 定义1.2、Zookeeper 工作机制1.3、Zookeeper 特点1.4、Zookeeper 数据结构1.5、Zookeeper 应用场景1.5、Zookeeper 选举机制1.5.1、 第一次启动选举机制1.5.2、 非第一次启动选举机制 二、Z…