Rust 所有权 简介
文章目录
- 发现宝藏
- 1. 所有权基本概念
- 2. 所有权规则
- 3. 变量作用域
- 4. 栈与堆
- 4.1 栈(Stack)
- 4.2 堆(Heap)
- 5. String类型
- 5.1 String 类型
- 5.2 String 的内存分配
- 5.3 所有权与内存管理
- 5.4 String 与切片
- 6. 变量与数据交互方式
- 6.1 移动(Move)
- 6.2. 克隆(Clone)
- 7. 所有权与函数
- 7.1. 传递参数
- 7.2. 返回值
- 总结
发现宝藏
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。
所有权(系统)是 Rust 最为与众不同的特性,它让 Rust 无需垃圾回收(garbage collector)即可保障内存安全。因此,理解 Rust 中所有权如何工作是十分重要的。我们将讲到所有权以及相关功能:借用、slice 以及 Rust 如何在内存中布局数据。
1. 所有权基本概念
所有权(ownership)是Rust的核心特性之一,它确保了内存安全,避免了内存泄漏等问题。每个值在Rust中都有一个所有者,即一个变量。每个值只能有一个所有者,当所有者离开作用域时,这个值将被自动丢弃。
2. 所有权规则
首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则:
- Rust 中的每一个值都有一个被称为其 所有者(owner)的变量。
- 值有且只有一个所有者。
- 当所有者(变量)离开作用域,这个值将被丢弃。
3. 变量作用域
在Rust中,变量的作用域是指变量在程序中有效的范围。当变量离开作用域时,其所有权的值将被自动清理。例如:
let s = "hello";
{let s = String::from("hello");// 使用 s
} // 此作用域已结束,s 不再有效
好的,让我们详细探讨 Rust 中的栈(Stack)与堆(Heap)存储,以及如何与所有权机制关联。
4. 栈与堆
在 Rust 中,数据可以存储在两种主要的内存区域:栈(Stack)和堆(Heap)。这两种存储方式各自具有不同的特性和用途。
4.1 栈(Stack)
栈是一种具有后进先出(LIFO)特性的内存结构。在栈上分配内存的过程非常高效,因为栈的内存分配和释放只涉及到栈顶指针的简单移动。
4.1.1 特点
- 固定大小:栈上存储的数据必须具有固定大小。在编译时,编译器知道数据的确切大小,因此可以在栈上进行高效的内存管理。
- 自动管理:栈上的数据在作用域结束时自动释放。这意味着栈上存储的局部变量会在其作用域结束时立即被销毁,栈指针会自动回退。
- 有限大小:栈的大小通常较小,超出栈的大小限制会导致栈溢出错误(Stack Overflow)。
4.1.2 示例
fn main() {let x = 42; // 整型数据存储在栈上let y = 3.14; // 浮点型数据存储在栈上let z = 'a'; // 字符型数据存储在栈上
}
在这个例子中,x
、y
和 z
都是固定大小的数据,它们会被分配在栈上。
4.2 堆(Heap)
堆是一种具有动态分配特性的内存区域,用于存储大小不固定的数据。堆上的内存分配不像栈那样高效,但它适用于需要动态内存管理的情况。
4.2.1 特点
- 动态大小:堆上的数据可以具有动态大小。你可以在运行时分配任意大小的内存,这使得堆非常适合存储不确定大小的数据。
- 手动管理:在 Rust 中,堆上的内存管理是自动的,由所有权机制管理。堆上的数据会在所有者超出作用域时自动释放。
- 可扩展:与栈相比,堆的大小受限较少,可以分配较大的内存块。
4.2.2 示例
fn main() {let s = String::from("Hello"); // 字符串在堆上分配内存
}
在这个例子中,String
是一个在堆上分配内存的动态数据结构。它的内存分配不再是固定的,而是由 String
类型内部的堆分配机制来处理。
5. String类型
以String类型为例,它存储在堆上,可以存储在编译时未知大小的文本。当我们创建一个String类型的变量时,实际上是在堆上分配了一块内存。
5.1 String 类型
在 Rust 中,String
是一个动态字符串类型,它与 &str
(字符串切片)不同。String
提供了可变的、可增长的字符串,可以在运行时修改其内容,并支持复杂的字符串操作。与 &str
不同的是,String
的内存分配是在堆上进行的。
5.1.1 String
的结构
String
类型的内部结构包括以下几个部分:
- 指针(Pointer):指向堆上实际存储字符串数据的位置。
- 长度(Length):当前字符串的字符数(字节数)。
- 容量(Capacity):堆上分配的总内存量,以字节为单位,通常比实际长度要大,以支持字符串的增长。
这个结构允许 String
具备动态扩展的能力,能够在需要时增长。
5.2 String 的内存分配
当你创建一个 String
实例时,Rust 会在堆上分配足够的内存来存储字符串数据。以下是 String
内存分配的关键步骤:
5.2.1 创建 String
fn main() {let s = String::from("Hello, world!"); // 创建一个新的 String
}
-
分配内存:Rust 会在堆上分配一块内存来存储字符串数据。在这个过程中,
String
会分配比实际需要的更多的内存,以便在未来的操作中能够容纳更多的字符。这种预分配机制有助于减少频繁的内存分配开销。 -
存储数据:字符串数据(例如
"Hello, world!"
)会被复制到堆上的内存中。此时,String
的指针指向堆上这块内存的起始位置。 -
更新元数据:
String
会维护内部的长度和容量信息。长度是当前存储的字符数,而容量是分配的总字节数。这样,Rust 可以有效管理字符串的增长和缩减。
5.2.2 动态增长
当你向 String
中添加更多字符时,Rust 会根据需要动态调整内存分配:
fn main() {let mut s = String::from("Hello");s.push_str(", world!"); // 动态增长
}
-
检查容量:
String
首先检查当前容量是否足够容纳新增的字符。如果足够,则直接在现有内存中追加字符。 -
重新分配:如果当前容量不足以容纳新数据,
String
会重新分配更大的堆内存,通常是原来容量的两倍。然后将旧数据复制到新分配的内存中,更新指针,最后释放旧内存。
5.3 所有权与内存管理
String
的内存管理由 Rust 的所有权系统自动处理,确保了内存的安全性和有效性:
-
所有权转移:当
String
的所有权转移到另一个变量时,堆上的数据也会随之转移,避免了数据的重复释放或访问无效内存的问题。fn main() {let s1 = String::from("Hello");let s2 = s1; // s2 现在拥有堆上的数据// println!("{}", s1); // 错误!s1 不再是有效的所有者println!("{}", s2); // 正确!s2 是有效的所有者 }
-
自动释放:当
String
的所有者超出作用域时,Rust 会自动调用String
的析构函数,释放堆上的内存。这防止了内存泄漏和资源泄漏。fn main() {{let s = String::from("Hello");// 使用 s} // s 超出作用域,堆内存被释放 }
5.4 String 与切片
虽然 String
是一个动态可变的字符串,但其内部可以借用不可变的字符串切片 &str
。这种方式允许在不拥有数据所有权的情况下安全地访问字符串的一部分:
fn main() {let s = String::from("Hello, world!");let slice: &str = &s[0..5]; // 切片借用字符串的一部分println!("{}", slice); // 输出 "Hello"
}
String
类型在 Rust 中提供了强大的动态字符串操作能力。它通过在堆上分配内存来支持可变长度的字符串,并利用 Rust 的所有权系统自动管理内存。了解 String
的内存分配和管理机制能够帮助你更好地编写高效、安全的 Rust 代码。
6. 变量与数据交互方式
6.1 移动(Move)
当将一个变量赋值给另一个变量时,Rust默认会进行移动操作,而非深拷贝。这意味着,原始变量的所有权会转移给新变量,原始变量将不再有效。
let s1 = String::from("hello");let s2 = s1; // s1 的所有权移动到 s2
6.2. 克隆(Clone)
如果我们需要深拷贝堆上的数据,可以使用clone方法。
let s1 = String::from("hello");let s2 = s1.clone(); // s2 是 s1 的深拷贝
7. 所有权与函数
7.1. 传递参数
将值传递给函数时,所有权会转移。如果函数参数是Copy类型的,则会进行拷贝;否则,会进行移动。
fn takes_ownership(some_string: String) {println!("{}", some_string);}fn makes_copy(some_integer: i32) {println!("{}", some_integer);}
7.2. 返回值
函数的返回值也可以转移所有权。通过返回值,我们可以将函数内部创建的值的所有权传递给外部。
fn gives_ownership() -> String {let some_string = String::from("hello");some_string}fn takes_and_gives_back(a_string: String) -> String {a_string}
总结
所有权是Rust语言的核心特性之一,它为内存管理提供了全新的解决方案。掌握所有权机制,有助于我们编写更安全、高效的Rust代码。虽然所有权概念在初学者看来较为复杂,但只要勤加练习,相信大家都能熟练运用。在后续的学习中,我们将继续探讨Rust的其他高级特性。
相关文章:
Rust 所有权 简介
文章目录 发现宝藏1. 所有权基本概念2. 所有权规则3. 变量作用域4. 栈与堆4.1 栈(Stack)4.2 堆(Heap) 5. String类型5.1 String 类型5.2 String 的内存分配5.3 所有权与内存管理5.4 String 与切片 6. 变量与数据交互方式6.1 移动&…...
linux-网络管理-防火墙配置
Linux 网络管理:防火墙配置 1. 防火墙概述 防火墙是保护计算机系统和网络免受未经授权访问和网络攻击的安全机制。Linux 系统中,防火墙通过控制进入和离开网络的数据包,实现网络流量的过滤和管理。 Linux 上的防火墙配置工具有多种&#x…...

【springboot】实现文件上传和下载
目录 1. 新建一个springboot项目2. 配置文件application.propertiesapplication.yml 3. 控制类实现文件上传和下载4. 测试 1. 新建一个springboot项目 新建一个springboot项目,选择web,默认即可. 主要pom配置文件如下: <parent><gr…...
【RabbitMQ】RabbitMQ如何保证数据的可靠性,RabbitMQ如何保证数据不丢失,数据存储
【RabbitMQ】RabbitMQ如何保证数据的可靠性,RabbitMQ如何保证数据不丢失,数据存储 RabbitMQ通过一系列机制来确保数据(即消息)在传输和处理过程中不丢失。这些机制主要包括以下几个方面: 1. 消息持久化 持久化消息&a…...

Redis 篇-初步了解 Redis 持久化、Redis 主从集群、Redis 哨兵集群、Redis 分片集群
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 分布式缓存概述 2.0 Redis 持久化 2.1 RDB 持久化 2.1.1 RDB 的 fork 原理 2.2 AOF 持久化 2.3 RDB 与 AOF 之间的区别 3.0 Redis 主从集群 3.1 搭建主从集群 3.2…...

算法基础-二分查找
左闭右闭 [ left,right ] [1,1]可以 while( left < right ) if( a[mid] > target ) right mid - 1 else if( a[mid] < target ) left mid 1 左闭右开 [ left,right ) …...
LeetCode:1184. 公交站间的距离 一次遍历数组,复杂度O(n)
1184. 公交站间的距离 today 1184 公交站间的距离 题目描述 环形公交路线上有 n 个站,按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离,distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都…...
牛客周赛 Round 60(A,B,C,D,E,F)
比赛链接 官方题解 这场基本都是数学题,官方题解讲的还不错,F能听懂的话其实不难。E是一个球盒模型的组合问题,F是化简递推式,成环时的解决方法很不错。 A 困难数学题 思路: 一个数异或两次结果为 0 0 0ÿ…...
vueCropper裁剪图片(不模糊)以及记录使用方法
需求:上传限定比例的图片。前端框架是vue3 element plus。 问题:使用vueCropper后比例固定。但是上传后的图片很模糊 vueCropper官网 解决办法 vueCropper中有一个full和high两个参数,记得开启 const options: any reactive({img: , // 原…...

【HTML】HTML页面和常见标签
文章目录 什么是前端HTML 页面编写如何快速生成代码框架常见标签注释标签标题标签段落标签换行标签格式化标签 什么是前端 Web 前端,用来直接给以用户呈现的一个一个的网页。一个软件通常是由 后端前端 完成的 后端:通过 Java/C等语言,完成相…...

鸿蒙 ArkUI组件二
ArkUI组件(续) 文本组件 在HarmonyOS中,Text/Span组件是文本控件中的一个关键部分。Text控件可以用来显示文本内容,而Span只能作为Text组件的子组件显示文本内容。 Text/Span组件的用法非常简单和直观。我们可以通过Text组件来显…...
PHP 实现 redis 分布式锁
分布式锁 如果是强一致性保证,在获取锁或者失败后引入数据库存储扫表、mq 等方式进行补偿 如果可以容忍少量异常就不需要考虑了 像这里的代码,没吃建立一个链接铺货,性能损耗时间延迟也是很大的,也可在一块代码中进行服务&…...

vue3 自定义el-tree树形结构样式
这里样式设置主要用到了 windcss 实现效果 模拟数据 这里也可以用模拟的数据,下面用的是后端请求的真实数据 [{"id": 5,"rule_id": 0,"status": 1,"create_time": "2019-08-11 13:36:09","update_time": "…...

【网络安全】分享4个高危业务逻辑漏洞
未经许可,不得转载。 文章目录 正文逻辑漏洞1逻辑漏洞2逻辑漏洞3逻辑漏洞4其它正文 该目标程序是一家提供浏览器服务的公司,其核心功能是网页抓取和多账户登录操作,类似于浏览器中的隐身模式,但更加强大和高效。通过该平台,用户可以轻松管理并同时运行数百个隐身浏览器实…...

【装机教程】Visual Studio Community 2019离线安装
Visual Studio 2019离线安装 由于现在 官网只支持在线安装最新版的Visual Studio 2022,因此 Visual Studio Community 2019需要离线安装。 下载离线安装镜像,并解压。点击vs_setup.exe运行。 选择安装位置,四处位置需要确定。 选择语言包&…...
NumPy 线性代数
NumPy 线性代数 NumPy 是 Python 中用于科学计算的核心库之一,它提供了一个强大的数学函数库,特别是在处理大型多维数组和矩阵时表现出色。线性代数是 NumPy 的一个重要组成部分,它包含了大量的函数和运算符,用于执行矩阵和向量的…...
家装材料之水泥,最容易被忽视的基础材料!
由于水泥在装修中扮演辅料的角色,很多业主往往会忽视它们的质量。事实上,装修无小事,不能抱有抓大放小的态度。 更何况水泥是装修工程的基础材料,在家居装修中,地面、墙面的找平以及瓷砖、大理石的铺贴&#…...

openstack之keystone介绍
功能 keystone在OpenStack中负责: 管理:用户、租户和权限; 认证:组件相互访问的身份认证; 鉴权:提供 RBAC(Role Based Access Control) 权限体系; 服务注册与发现&#…...

【图像拼接】基于SIFT/SURF特征算法的图像拼接,matlab实现
博主简介:matlab图像代码项目合作(扣扣:3249726188) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于SIFT/SURF特征算法的图像拼接,用matlab实现。 一、案例背景和算法介…...

《微信小程序实战(2) · 组件封装》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...