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入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
PLC入门【4】基本指令2(SET RST)
04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C),从 文件 - 主画面,“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…...
