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的其他高级特性。

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

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

相关文章

全球NAND原厂闪存市场格局变化

根据市场研究机构TrendForce的最新跟踪报告,三星(Samsung)和SK海力士(SK hynix-Solidigm)在过去的一个季度中扩大了他们在NAND闪存市场的份额,这主要得益于抢占了铠侠(Kioxia)与西部…

小目标检测顶会新思路!最新成果刷爆遥感SOTA,参数小了18倍

遥感领域的小目标检测一直是个具有挑战性和趣味性的研究方向,同时也是顶会顶刊的常客。但不得不说,今年关于遥感小目标检测的研究热情尤其高涨,已经出现了很多非常优秀的成果。 比如SuperYOLO方法,通过融合多模态数据并执行高分辨…

【重学 MySQL】二十八、SQL99语法新特性之自然连接和 using 连接

【重学 MySQL】二十八、SQL99语法新特性之自然连接和 using 连接 自然连接(NATURAL JOIN)USING连接总结 SQL99语法在SQL92的基础上引入了一些新特性,其中自然连接(NATURAL JOIN)和USING连接是较为显著的两个特性。 自…

数据结构(14)——哈希表(1)

欢迎来到博主的专栏:数据结构 博主ID:代码小豪 文章目录 哈希表的思想映射方法(哈希函数)除留余数法 哈希表insert闭散列负载因子扩容find和erase 哈希表的思想 在以往的线性表中,查找速度取决于线性表是否有序&#…

知识库管理系统在企业数字化转型中的作用

引言 在数字化转型的浪潮中,企业正以前所未有的速度重塑其业务模式、运营流程和组织架构,以适应快速变化的市场环境和客户需求。这一过程中,知识库管理系统作为信息整合与知识共享的核心平台,发挥着举足轻重的作用,不…

【解决】AnimationCurve 运行时丢失数据问题

开发平台:Unity 2022 编程平台:Visual Studio 编程语言:CSharp   一、问题背景 如上图所示的 GracityComponent 组件中,引用 AnimationCurve 作为可调属性。但在实际使用中出现数据丢失问题。大致为以下两种情况: 运…

【重学 MySQL】二十七、七种 join 连接

【重学 MySQL】二十七、七种 join 连接 union 的使用UNION 的基本用法示例UNION ALL 的用法 七种 join 连接代码实现语法格式小结 union 的使用 UNION 在 SQL 中用于合并两个或多个 SELECT 语句的结果集,并默认去除重复的行。如果希望包含重复行,可以使…

RNN发展(RNN/LSTM/GRU/GNMT/transformer/RWKV)

RNN到GRU参考: https://blog.csdn.net/weixin_36378508/article/details/115101779 tRANSFORMERS参考: seq2seq到attention到transformer理解 GNMT 2016年9月 谷歌,基于神经网络的翻译系统(GNMT),并宣称GNMT在多个主…

java程序员入行科目一之CRUD轻松入门教程(二)

封装工具类 封装获取连接&释放资源操作 在实际使用JDBC的时候,很多操作都是固定的,没有必要每次都去注册驱动,获取链接对象等等。 同样,释放资源的close操作也可以封装一下 下面是封装好的具体工具类 package com.jimihua.u…

海外云手机是否适合运营TikTok?

随着科技的迅猛发展,海外云手机逐渐成为改变工作模式的重要工具。这种基于云端技术的虚拟手机,不仅提供了更加便捷、安全的使用体验,还在电商引流和海外社媒管理等领域展示了其巨大潜力。那么,海外云手机究竟能否有效用于运营TikT…

mosh java 2.4 inheritance继承

1.面向对象编程的第三个特点 继承 继承的好处 java不能继承多个父级 代码文件结构 1.main.java package org.example; //package org.codewithme;//import org.example.UIControl;//TIP To <b>Run</b> code, press <shortcut actionId"Run"/> or /…

3C电子胶黏剂在手机制造方面有哪些关键的应用

3C电子胶黏剂在手机制造方面有哪些关键的应用 3C电子胶黏剂在手机制造中扮演着至关重要的角色&#xff0c;其应用广泛且细致&#xff0c;覆盖了手机内部组件的多个层面&#xff0c;确保了设备的可靠性和性能。以下是电子胶在手机制造中的关键应用&#xff1a; 手机主板用胶&…

率先搭载存内计算AI芯片,维迈通引领骑行通讯降噪革新

近日&#xff0c;高端骑行头盔耳机领导品牌维迈通&#xff08;VIMOTO&#xff09;三款新品XR、V10S、V10X全平台正式发售&#xff0c;创新搭载了知存科技&#xff08;Witmem&#xff09;高能效存内计算AI芯片&#xff0c;为骑行爱好者带来更极致的AI降噪体验。 作为一家专注摩托…

状压DP

状压DP 对于数据范围n<20的可以考虑状压DP 1.蒙德里安的梦想 题目描述 求把 N M NM NM 的棋盘分割成若干个 12 的的长方形&#xff0c;有多少种方案。 例如当$ N2&#xff0c;M4$ 时&#xff0c;共有 5 种方案。当 N 2 &#xff0c; M 3 N2&#xff0c;M3 N2&…

windows 创建新用户,并分配到指定组

右击电脑 -> 点击管理 在右边右击&#xff0c;选择新用户&#xff0c;输入相关信息创建 创建用户后&#xff0c;选择用户&#xff0c;右击&#xff0c;选择属性&#xff0c;添加 点击高级 点击立即查找&#xff0c;可以搜索出所有可用的组&#xff0c;为其选择即可

Java XML

1、XML文件介绍 配置文件&#xff1a;用来保存设置的一些东西。 拿IDEA来举例&#xff0c;比如设置的背景图片&#xff0c;字体信息&#xff0c;字号信息和主题信息等等。 &#xff08;1&#xff09;以前是用txt保存的&#xff0c;没有任何优点&#xff0c;而且不利于阅读&a…

停车位检测-停车场车位识别

YOLO Parking Spot 概述 停车场获取的图像训练了四个YOLO模型来检测车辆。目标是收集信息&#xff0c;并可能开发一种停车解决方案以改善交通流量并优化空间利用率。通过识别汽车&#xff0c;我们生成了一份报告&#xff0c;其中包含图像细节&#xff0c;如可用停车位的数量、…

官宣:Zilliz 在亚马逊云科技中国区正式开服!

01 Zilliz Cloud 正式上线亚马逊云科技宁夏区服务 9 月 4 日&#xff0c;Zilliz 正式官宣&#xff0c; Zilliz Cloud 正式上线亚马逊云科技在宁夏区的云服务。至此&#xff0c;Zilliz Cloud 已实现全球 5 大云 19 个节点 的全覆盖&#xff0c;成为全球首个提供海内外多云服务的…

《机器学习》—— SVD奇异值分解方法对图像进行压缩

文章目录 一、SVD奇异值分解简单介绍二、代码实现—SVD奇异值分解方法对图像进行压缩 一、SVD奇异值分解简单介绍 SVD&#xff08;奇异值分解&#xff09;是一种在信号处理、统计学、线性代数、机器学习等多个领域广泛应用的矩阵分解方法。它将任何 mn 矩阵 A 分解为三个特定矩…

从0书写一个softmax分类 李沐pytorch实战

输出维度 在softmax 分类中 我们输出与类别一样多。 数据集有10个类别&#xff0c;所以网络输出维度为10。 初始化权重和偏置 torch.norma 生成一个均值为 0&#xff0c;标准差为0.01,一个形状为size(num_inputs, num_outputs)的张量偏置生成一个num_outputs 10 的一维张量&a…