Rust 学习笔记:Box<T>

Rust 学习笔记:Box

  • Rust 学习笔记:Box<T\>
    • Box\<T> 简介
    • 使用 Box\<T\> 在堆上存储数据
    • 启用带有 box 的递归类型
      • 关于 cons 列表的介绍
      • 计算非递归类型的大小
      • 使用 Box\<T\> 获取大小已知的递归类型

Rust 学习笔记:Box<T>

指针是在内存中包含地址的变量的一般概念。这个地址引用或“指向”其他一些数据。在 Rust 中最常见的指针类型是引用,由 & 符号表示,并借用它们所指向的值。除了引用数据之外,它们没有任何特殊功能,也没有开销。

智能指针是一种像指针一样的数据结构,但还具有额外的元数据和功能。Rust 在标准库中定义了各种智能指针,这些指针提供的功能超出了引用所提供的功能。

具有所有权和借用概念的 Rust 在引用和智能指针之间有一个额外的区别:引用只借用数据,而在许多情况下,智能指针拥有它们所指向的数据。

我们遇到了一些智能指针:String 和 Vec<T>。这两种类型都算作智能指针,因为它们拥有一些内存,并允许对其进行操作。它们还具有元数据和额外的功能或保证。例如,String 将其容量存储为元数据,并具有确保其数据始终是有效的 UTF-8 的额外能力。

智能指针通常使用结构体实现。与普通结构体不同,智能指针实现了 Deref 和Drop trait。Deref trait 允许智能指针结构体的实例表现得像引用一样,这样就可以编写代码来使用引用或智能指针。Drop trait 允许自定义当智能指针的实例超出作用域时运行的代码。

Box<T> 简介

最直接的智能指针是 Box<T>,它运行将数据存储在堆中而不是栈中,留在栈上的是指向堆数据的指针。

Box<T> 没有性能开销,但它们也没有太多额外的功能。最常在以下情况下使用它:

  • 当你的类型在编译时无法知道其大小,并且你希望在需要精确大小的上下文中使用该类型的值时

  • 当你有大量的数据,你想要转移所有权,但要确保数据不会被复制时

  • 当你想拥有一个值,你只关心它是一个实现了特定特性的类型,而不是一个特定的类型

我们将在下文中演示第一种情况。在第二种情况下,传输大量数据的所有权可能需要很长时间,因为数据是在栈上复制的。为了在这种情况下提高性能,我们可以将大量数据存储在堆中的盒子中。然后,只有少量的指针数据在栈上被复制,而它引用的数据留在堆上的一个地方。第三种情况被称为 trait 对象,后续文章将专门讨论了这个主题。

使用 Box<T> 在堆上存储数据

首先介绍 Box<T> 的语法以及如何与存储在 Box<T> 中的值进行交互。

fn main() {let b = Box::new(5);println!("b = {b}");
}

我们将变量 b 定义为具有指向值 5 的 box 的值,该值在堆上分配。这个程序将输出 b = 5。在这种情况下,我们可以访问 box 中的数据,就像我们访问栈中的数据一样。

当一个 box 超出作用域时,就像 main 语句末尾的 b 变量那样,它将被释放。对 box(存储在栈上)和它所指向的数据(存储在堆上)都进行释放。

将单个值放在堆上并不是很有用,在栈上使用单个 i32 这样的值更合适。

Box<T> 在定义类型时更有用。

启用带有 box 的递归类型

递归类型的值可以有另一个相同类型的值作为其本身的一部分。递归类型造成了一个问题,因为 Rust 需要在编译时知道一个类型占用了多少空间。然而,递归类型的值的嵌套理论上可以无限地继续下去,因此 Rust 无法知道值需要多少空间。因为 box 的大小是已知的,所以我们可以通过在递归类型定义中插入一个 box 来启用递归类型。

作为递归类型的一个示例,让我们研究一下 cons 列表。这是函数式编程语言中常见的一种数据类型。

关于 cons 列表的介绍

cons 列表是一种来自 Lisp 编程语言的数据结构,由嵌套对组成,是 Lisp 版本的链表。它的名字来自于 Lisp 中的c ons 函数(construct function 的缩写),它从它的两个参数构造一个新的 pair。通过对由一个值和另一个值组成的对调用 cons,我们可以构造由递归对组成的 cons 列表。

例如,下面是一个 cons 列表的伪代码表示,其中包含列表 1、2、3,每一对都在括号中:

(1, (2, (3, Nil)))

cons 列表中的每一项包含两个元素:当前项的值和下一项的值。列表中的最后一项只包含一个名为 Nil 的值,没有下一项。

cons 列表不是Rust中常用的数据结构。但从本章的 cons 列表开始,我们可以探索 box 如何让我们定义递归数据类型。

下列代码包含了 cons 列表的枚举定义。

enum List {Cons(i32, List),Nil,
}

注意,这段代码还不能编译,因为 List 类型没有已知的大小,我们将对此进行演示。

尝试构建一个 cons 列表:

use crate::List::{Cons, Nil};fn main() {let list = Cons(1, Cons(2, Cons(3, Nil)));
}

第一个 Cons 值保存 1 和另一个 List 值。这个 List 值是另一个 Cons 值,它包含 2 和另一 List 值。这个 List 值是另一个 Cons 值,它包含 3 和一个 List 值,最后是 Nil,这是表示列表结束的非递归变体。

尝试运行这段代码,报错:

在这里插入图片描述

错误显示 List 类型“具有无限大小”。原因是我们用递归的变量定义了 List:它直接保存自身的另一个值。因此,Rust 无法计算出它需要多少空间来存储 List 值。

让我们分析一下为什么会出现这个错误。首先,我们来看一下 Rust 如何决定存储非递归类型的值需要多少空间。

计算非递归类型的大小

以一个 Message 枚举为例:

enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}

为了确定为 Message 值分配多少空间,Rust 遍历每个变体,以查看哪个变体需要最多的空间。Message::Quit 不需要任何空间,Message::Move 占用两个 i32 值大小的空间,以此类推。因为只使用一个变体,所以 Message 值所需的最大空间就是存储其最大变体所需的空间。

与此形成对比的是,当 Rust 试图确定 List 枚举这样的递归类型需要多少空间时发生的情况。编译器首先查看 Cons 变量,它包含一个 i32 类型的值和一个 List 类型的值。因此,Cons 需要的空间量等于 i32 的大小加上 List 的大小。为了计算出 List 类型需要多少内存,编译器从 Cons 变量开始,这个过程无限地继续下去。

在这里插入图片描述

使用 Box<T> 获取大小已知的递归类型

因为 Rust 不能计算出为递归定义的类型分配多少空间,编译器给出了一个错误,并给出了这个有用的建议:

在这里插入图片描述

在这个建议中,间接意味着不是直接存储一个值,而是通过存储指向该值的指针来改变数据结构,从而间接存储该值。

因为 Box<T> 是一个指针,指针的大小不会根据它所指向的数据量而改变。这意味着我们可以在 Cons 变量中放入 Box<T>,而不是直接放入另一个 List 值。Box<T> 将指向下一个 List 值,该值将位于堆上,而不是在 Cons 变量中。

从概念上讲,我们仍然有一个列表,创建了包含其他列表的列表。但是这个实现现在更像是将项放在另一个项旁边,而不是放在另一个项内部。

修改代码:

enum List {Cons(i32, Box<List>),Nil,
}use crate::List::{Cons, Nil};fn main() {let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}

一个 Cons 变量 = 一个 i32 + 一个Box<T> 指针。Nil 不存储任何值,因此它比 Cons 变量需要更少的空间。通过使用盒子,我们打破了无限的递归链,因此编译器可以计算出存储 List 值所需的大小。

在这里插入图片描述

盒子只提供间接分配和堆分配,没有任何其他特殊功能,也没有这些特殊功能所带来的性能开销,因此它们在像 cons 列表这样的情况下非常有用,其中间接是我们唯一需要的特性。

Box<T> 类型是一个智能指针,因为它实现了 Deref trait,它允许 Box<T> 值被当作引用来对待。当 Box<T> 值超出作用域时,由于 Drop trait 的实现,该指针所指向的堆数据也会被清理。

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

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

相关文章

英语写作中“不少于(小于)”no less than替代no fewer than的用法

no less than 1 liter of water&#xff0c;no fewer than 100 people 是我们的传统用法。现代英语有一个有趣的现象&#xff0c;就是less 代替fewer 形容可数名词&#xff0c;例如&#xff1a; Do you have 10 courses each week? No. We have less. 显然按严格语法应该是…

竞品分析六大步骤

一、引言 在产品打磨、市场推广或战略定位过程中&#xff0c;我们常常会面临一个关键任务——竞品分析。一份系统的竞品分析不仅能帮助我们知己知彼&#xff0c;优化产品策略&#xff0c;更能成为决策层制定方向的重要依据。竞品分析到底该怎么做&#xff1f;今天我将结合自己的…

【Java Web】9.Maven高级

&#x1f4d8;博客主页&#xff1a;程序员葵安 &#x1faf6;感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb; 文章目录 一、分模块设计与开发 1.1 介绍 1.2 实践 二、继承与聚合 2.1 继承 继承关系 版本锁定 2.2 聚合 2.3 继承与聚合对比 三、…

MySQL 全量、增量备份与恢复

一.MySQL 数据库备份概述 备份的主要目的是灾难恢复&#xff0c;备份还可以测试应用、回滚数据修改、查询历史数据、审计等。之前已经学习过如何安装 MySQL&#xff0c;本小节将从生产运维的角度了解备份恢复的分类与方法。 1 数据备份的重要性 在企业中数据的价值至关…

第六个微信小程序:教师工具集

源于工作需要&#xff0c;下面开始。 安装及使用 | Taro 文档 vscode 代码管理 git 辅助 开发技术如上&#xff1a; 1.开始创建模板 taro4.1.1 $ taro init teachers-tools 2.用vsocde开始吧。 选择 第二个文件夹找一。 (base) PS D:\react\teachers-tools> pnpm…

Linux 里 su 和 sudo 命令这两个有什么不一样?

《小菜狗 Linux 操作系统快速入门笔记》目录&#xff1a; 《小菜狗 Linux 操作系统快速入门笔记》&#xff08;01.0&#xff09;文章导航目录【实时更新】 Linux 是一个多用户的操作系统。在 Linux 中&#xff0c;理论上来说&#xff0c;我们可以创建无数个用户&#xff0c;但…

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …

服务器被攻击了怎么办

可以上一个高防IP或者AI云防护都是可以的。&#xff08;有效防御CC、APl接口、http、tcp、WEB应用扫描/爬虫、SYN、WAF、DDOS、UDP、入侵、渗透、SQL注入、XSS跨站脚本攻击、远程恶意代码执行、session fixation、Webshell攻击、恶意请求&#xff0c;恶意扫描、暴力破解、CSRF等…

【学习笔记】Circuit Tracing: Revealing Computational Graphs in Language Models

Circuit Tracing: Revealing Computational Graphs in Language Models 替代模型(Replacement Model)&#xff1a;用更多的可解释的特征来替代transformer模型的神经元。 归因图(Attribution Graph)&#xff1a;展示特征之间的相互影响&#xff0c;能够追踪模型生成输出时所采用…

灵活控制,modbus tcp转ethernetip的 多功能水处理方案

油田自动化和先进的油气行业软件为油气公司带来了诸多益处。其中包括&#xff1a; 1.自动化可以消除多余的步骤、减少人为错误并降低运行设备所需的能量&#xff0c;从而降低成本。 2.油天然气行业不断追求高水平生产。自动化可以更轻松地减少计划外停机时间&#xff0c;从而…

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…

windows VeraCrypt – 磁盘加密工具

下载链接&#xff1a;夸克网盘分享 VeraCrypt一款跨平台(Windows/Mac/Linux)的磁盘加密工具&#xff0c;提供多层级数据保护方案&#xff1a;虚拟加密盘&#xff1a;在文件中创建可挂载的加密虚拟磁盘全设备加密&#xff1a;支持分区/USB/硬盘等存储设备的全盘加密系统盘加密&…

客户体验数据使用的三种视角——场景视角

当企业收集到大量的客户体验数据之后&#xff0c;应该如何应用&#xff1f;有哪些主要的使用场景和分析视角&#xff1f;体验家团队通过三篇文章&#xff0c;陆续介绍三种体验数据的使用场景&#xff0c;以帮助企业更有效地利用体验数据进行改进。 01 宏观层次的“旅程视角” …

时序数据库IoTDB的UDF Sample算法在数据监控、故障预防的应用

一、数据监控在工业物联网中的重要性 设备数据监控是工业物联网&#xff08;IoT&#xff09;中最为广泛应用的领域之一。通过实时监控工厂机械设备的运行状态&#xff0c;企业能够提前发现设备的潜在故障&#xff0c;从而实现预防性维护与可预测性维护。这一做法不仅能有效提升…

fastadmin fildList 动态下拉框默认选中

html页面 <td><select class"form-control dtselect" data-rule"required" data-dtselected"<%row.type%>" name"<%name%>[<%index%>][type]">{foreach nametypeList idvo}<option value"{$vo…

Python 入门到进阶全指南:从语言特性到实战项目

一、Python 简介 Python 是一种高级、跨平台、解释型编程语言&#xff0c;以简洁语法和高可读性著称&#xff0c;既适合编程初学者快速入门&#xff0c;也能满足资深开发者的复杂需求。其核心特性与应用场景如下&#xff1a; 核心特性解析 解释型语言&#xff1a;无需编译即可…

【unity游戏开发入门到精通——通用篇】从零掌握UnityWebRequest:文件下载、表单提交、超时处理、断点续传

文章目录 一、UnityWebRequest 与 WWW 的比较二、核心组件三、常用方法四、基本使用示例1. GET请求2. POST请求五、实用功能1. 下载进度显示2. 断点续传实现3. 文件上传到服务器六、使用建议七、性能优化专栏推荐完结一、UnityWebRequest 与 WWW 的比较 UnityWebRequest 是 Un…

使用 Flutter 开发 App 时,想要根据 Figma 设计稿开发出响应式 UI 界面

在使用 Flutter 开发 App 时&#xff0c;想要根据 Figma 设计稿开发出响应式 UI 界面&#xff08;Responsive UI&#xff09;&#xff0c;以适配不同尺寸和分辨率的手机设备&#xff0c;需要从 设计阶段 和 编码实现阶段 双向配合。以下是详细的实现思路与方法&#xff1a; &am…

【计算机网络】网络层协议

1. ICMP协议的介绍及应用 IP协议的助手 —— ICMP 协议 ping 是基于 ICMP 协议工作的&#xff0c;所以要明白 ping 的工作&#xff0c;首先我们先来熟悉 ICMP 协议。 ICMP 全称是 Internet Control Message Protocol&#xff0c;也就是互联网控制报文协议。 里面有个关键词 …

LabVIEW准分子激光器智能控制系统

LabVIEW 开发准分子激光器智能控制系统&#xff0c;针对放电激励型准分子激光器强电磁干扰环境下的控制难题&#xff0c;采用 “PC 端 LabVIEW 人机交互 MCU 端实时控制 光纤隔离通信” 架构&#xff0c;实现激光能量闭环控制、腔体环境监测、气路自动管理等功能。硬件选用 N…