当前位置: 首页 > news >正文

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 特点

  1. 固定大小:栈上存储的数据必须具有固定大小。在编译时,编译器知道数据的确切大小,因此可以在栈上进行高效的内存管理。
  2. 自动管理:栈上的数据在作用域结束时自动释放。这意味着栈上存储的局部变量会在其作用域结束时立即被销毁,栈指针会自动回退。
  3. 有限大小:栈的大小通常较小,超出栈的大小限制会导致栈溢出错误(Stack Overflow)。

4.1.2 示例

fn main() {let x = 42; // 整型数据存储在栈上let y = 3.14; // 浮点型数据存储在栈上let z = 'a'; // 字符型数据存储在栈上
}

在这个例子中,xyz 都是固定大小的数据,它们会被分配在栈上。

4.2 堆(Heap)

堆是一种具有动态分配特性的内存区域,用于存储大小不固定的数据。堆上的内存分配不像栈那样高效,但它适用于需要动态内存管理的情况。

4.2.1 特点

  1. 动态大小:堆上的数据可以具有动态大小。你可以在运行时分配任意大小的内存,这使得堆非常适合存储不确定大小的数据。
  2. 手动管理:在 Rust 中,堆上的内存管理是自动的,由所有权机制管理。堆上的数据会在所有者超出作用域时自动释放。
  3. 可扩展:与栈相比,堆的大小受限较少,可以分配较大的内存块。

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
}
  1. 分配内存:Rust 会在堆上分配一块内存来存储字符串数据。在这个过程中,String 会分配比实际需要的更多的内存,以便在未来的操作中能够容纳更多的字符。这种预分配机制有助于减少频繁的内存分配开销。

  2. 存储数据:字符串数据(例如 "Hello, world!")会被复制到堆上的内存中。此时,String 的指针指向堆上这块内存的起始位置。

  3. 更新元数据String 会维护内部的长度和容量信息。长度是当前存储的字符数,而容量是分配的总字节数。这样,Rust 可以有效管理字符串的增长和缩减。

5.2.2 动态增长

当你向 String 中添加更多字符时,Rust 会根据需要动态调整内存分配:

fn main() {let mut s = String::from("Hello");s.push_str(", world!"); // 动态增长
}
  1. 检查容量String 首先检查当前容量是否足够容纳新增的字符。如果足够,则直接在现有内存中追加字符。

  2. 重新分配:如果当前容量不足以容纳新数据,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项目&#xff0c;选择web&#xff0c;默认即可. 主要pom配置文件如下&#xff1a; <parent><gr…...

【RabbitMQ】RabbitMQ如何保证数据的可靠性,RabbitMQ如何保证数据不丢失,数据存储

【RabbitMQ】RabbitMQ如何保证数据的可靠性&#xff0c;RabbitMQ如何保证数据不丢失&#xff0c;数据存储 RabbitMQ通过一系列机制来确保数据&#xff08;即消息&#xff09;在传输和处理过程中不丢失。这些机制主要包括以下几个方面&#xff1a; 1. 消息持久化 持久化消息&a…...

Redis 篇-初步了解 Redis 持久化、Redis 主从集群、Redis 哨兵集群、Redis 分片集群

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 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&#xff0c;right ] [1,1]可以 while( left < right ) if( a[mid] > target ) right mid - 1 else if( a[mid] < target ) left mid 1 左闭右开 [ left&#xff0c;right ) …...

LeetCode:1184. 公交站间的距离 一次遍历数组,复杂度O(n)

1184. 公交站间的距离 today 1184 公交站间的距离 题目描述 环形公交路线上有 n 个站&#xff0c;按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离&#xff0c;distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都…...

牛客周赛 Round 60(A,B,C,D,E,F)

比赛链接 官方题解 这场基本都是数学题&#xff0c;官方题解讲的还不错&#xff0c;F能听懂的话其实不难。E是一个球盒模型的组合问题&#xff0c;F是化简递推式&#xff0c;成环时的解决方法很不错。 A 困难数学题 思路&#xff1a; 一个数异或两次结果为 0 0 0&#xff…...

vueCropper裁剪图片(不模糊)以及记录使用方法

需求&#xff1a;上传限定比例的图片。前端框架是vue3 element plus。 问题&#xff1a;使用vueCropper后比例固定。但是上传后的图片很模糊 vueCropper官网 解决办法 vueCropper中有一个full和high两个参数&#xff0c;记得开启 const options: any reactive({img: , // 原…...

【HTML】HTML页面和常见标签

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

鸿蒙 ArkUI组件二

ArkUI组件&#xff08;续&#xff09; 文本组件 在HarmonyOS中&#xff0c;Text/Span组件是文本控件中的一个关键部分。Text控件可以用来显示文本内容&#xff0c;而Span只能作为Text组件的子组件显示文本内容。 Text/Span组件的用法非常简单和直观。我们可以通过Text组件来显…...

PHP 实现 redis 分布式锁

分布式锁 如果是强一致性保证&#xff0c;在获取锁或者失败后引入数据库存储扫表、mq 等方式进行补偿 如果可以容忍少量异常就不需要考虑了 像这里的代码&#xff0c;没吃建立一个链接铺货&#xff0c;性能损耗时间延迟也是很大的&#xff0c;也可在一块代码中进行服务&…...

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&#xff0c;因此 Visual Studio Community 2019需要离线安装。 下载离线安装镜像&#xff0c;并解压。点击vs_setup.exe运行。 选择安装位置&#xff0c;四处位置需要确定。 选择语言包&…...

NumPy 线性代数

NumPy 线性代数 NumPy 是 Python 中用于科学计算的核心库之一&#xff0c;它提供了一个强大的数学函数库&#xff0c;特别是在处理大型多维数组和矩阵时表现出色。线性代数是 NumPy 的一个重要组成部分&#xff0c;它包含了大量的函数和运算符&#xff0c;用于执行矩阵和向量的…...

家装材料之水泥,最容易被忽视的基础材料!

由于水泥在装修中扮演辅料的角色&#xff0c;很多业主往往会忽视它们的质量。事实上&#xff0c;装修无小事&#xff0c;不能抱有抓大放小的态度。      更何况水泥是装修工程的基础材料&#xff0c;在家居装修中&#xff0c;地面、墙面的找平以及瓷砖、大理石的铺贴&#…...

openstack之keystone介绍

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

【图像拼接】基于SIFT/SURF特征算法的图像拼接,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于SIFT/SURF特征算法的图像拼接&#xff0c;用matlab实现。 一、案例背景和算法介…...

《微信小程序实战(2) · 组件封装》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...