Rust 学习笔记:Box<T>

Rust 语言特性:智能指针 Box<T> 本文介绍了Rust中智能指针的概念及其应用,重点分析了Box<T>这一基础智能指针。作者指出Rust通过Box<T>等机制避免直接操作裸指针带来的内存隐患,并以递归类型cons list为例,说明如何用Box<T>解决类型无限递归问题。当定义递归类型时,Box<T>作为间接层能固定类型大小,将实际数据存储在堆上,而指针本身(固定大小)存储在栈上,从而满足编译要求。文中示例展示了使用Box<List>构建可编译通过的递归链表,体现了Rust通过智能指针实现内存安全的核心理念。 阅读详情

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 的实现,该指针所指向的堆数据也会被清理。

SCHUNK SVH五指灵巧手 | 熵洛智能 雄克仿真五指机械手产品系列可以如人手操作那般完美地完成抓取操作。电子装置完全集成于腕关节中,使五指机械手几乎可以完成所有的人体手部动作。凭借带有9个驱动器的运动指骨,机械手可高精度地 执行多种抓取操作。富有弹性的抓取表面确保了对物体的可靠抓取。除了开启抓取和操作任务的全新领域之外,雄克还为在五指机械手的手势基础上进行人与机器人的交流开创了无限可能。编辑切换为居中添加图片注释,不超过 140 字(可选)产品特点:机械手有左手或右手两种版本适合移动应用耗能低,使用 24 V DC 在腕关节处完整集成了控制、调节 阅读详情

相关推荐

Cadence SIP Layout 简单教程-第一章

以摄像头模组软硬结合板为例,描述layout的整个完整过程,从而掌握基本技能。 第一章 准备工作 第一节 原理图不用说layout前需要绘制原理图,原理图不在本文讨论范围内,所以列为准备工作。 需要特别说明的是,绘制原理的最终目的是导出网络表,网络表中的重要参数footprint是让layout软件选择正确封装的关键,所以这里讲解一下原理图设置footprint的位置。在原理图中双击零件,...

whp1920的博客 1万+

Rust中Box、Rc、Arc、Cell、RefCell、Cow简介

一、Box 是一种独享所有权智能指针,类似C++的unique_ptr 资源分配在堆上,依靠Deref和Drop来管理堆上的资源,零运行时开销,是最常用的套娃。 Box::new(v) : 创建,移动语义,独占所有权 - move,允许使用*转移本体所有权 不可变借用:Box::borrow()、Box::as_ref()、Box::deref() 可变借用:Box::borrow_mut()、Box::as_mut()、Box::deref_mut() 二、Rc是一种共享所有权智能指针,类似C++的s

rayylee 8713

OpenWRT软件源更换保姆级教程:从国内镜像到官方源一键切换(含常见报错解决)

本文提供OpenWRT软件源更换的详细教程,涵盖从国内镜像源到官方源的切换方法,并深度解析常见报错解决方案。针对国内网络环境,指导用户如何精准定位系统信息、备份配置、选择并配置清华等国内镜像源,以及处理签名验证失败、依赖缺失、404错误等典型问题,旨在提升软件包管理效率与稳定性。

weixin_29229261的博客 1935

【Rust 基础篇】Rust Box 智能指针

Box是一个指向堆上分配的值的指针。它提供了所有权转移和释放内存的功能。使用Box智能指针,可以在编译时保证内存安全,避免悬挂指针和内存泄漏等问题。Box在栈上存储指针,指向堆上的数据。在转移所有权时负责释放堆上的内存。大小固定,适用于已知大小的类型。只能有一个所有者,不可共享引用。本篇博客详细介绍了 Rust 中的Box智能指针的使用方法和特性。Box提供了堆分配和所有权转移的功能,可以在编译时保证内存安全,并解决递归类型的问题。希望本篇博客对你理解和应用 Rust 中的Box。

繁依Fanyi的博客 1936

从学生项目到工程实践:手把手教你用ATE测试电源芯片的Rdson与漏电流

本文详细介绍了如何将学术级的电源芯片测试方案转化为工业级解决方案,重点讲解使用ATE设备测试Rdson(导通电阻)和漏电流的关键技术。从设备选型、测试夹具设计到量产环境下的工程化实现,提供了实用的优化技巧和常见问题解决方案,帮助工程师提升测试效率和精度。

weixin_42525289的博客 180

《缠中说禅108课》5:市场无须分析,只要看和干

喜欢吹牛皮的,在市场里最常见,例如一种以分析市场、吹牛皮为生的职业,叫什么股评、专家的。此类人不过是市场上的寄生虫,真正的猎手只会观察、操作,用嘴是打不了豺狼的。 市场就是一个狩猎场,首先你要成为一个好猎手,而一个猎手,首先要习惯于无言。如果真有什么真理,那真理也是无言的。可言说的,都不过是人类思想的分泌物,臭气熏天。真不可言说了,就无不可言,言而无言,是乃真言。 一个好的猎手,可以没有嘴巴,但一定会有一双不为外物所动的眼睛,在这眼睛下,一切如幻化般透明。要不被外物所动,则首先要不被自我所迷惑,其实..

BenRen1314的博客 800

Rust: Box 智能指针进阶 - Rc、RefCell、Weak

Rust: Box 智能指针进阶 - Rc、RefCell、Weak 文章目录Rust: Box 智能指针进阶 - Rc、RefCell、Weak正文1. Box 类型复习2. 自定义模拟 Box 类型3. 递归类型定义4. Box 进阶:Rc5. Box 进阶:RefCell6. 循环依赖 & Weak7. 结论其他资源参考连接完整代码示例 正文 1. Box 类型复习 Rust 内置类型: Box、Option、Result Box 为一种特别的引用类型,实际数据存储在堆上 Box 作为引用类

超悠閒的博客 2653

【异常】Coze/扣子 Workflow 调用报 4200 错误深度解析

Coze API 的。

奶爸的编程之路,也就一周冷个三天 301

Rust 中 Box 的深度解析:作用、原理与最佳实践

Rust中的Box是核心智能指针,主要用于堆内存分配、所有权转移和解决递归类型问题。它将数据从栈移到堆,适用于大型数据或需要延长生命周期的场景。Box实现独占所有权和自动释放,编译后效率与手动管理相同。关键应用场景包括处理递归数据结构、实现trait对象、优化大数据传递和构建复杂类型。相比其他智能指针,Box开销最小但不支持共享所有权。最佳实践建议优先使用栈分配,必要时采用Box来防止栈溢出或减少复制开销。Box体现了Rust零成本抽象与安全内存管理的核心设计理念。

程序猿视角 1858

K230在原有LVGL控件触摸屏控制的基础上,增加USB鼠标控制!

搭配CanMV图形化编程,中小学生可快速开发“键鼠控制AI小游戏”“智能画板”等趣味项目,降低AI学习门槛;:HDMI屏幕+键鼠组合,直接在开发板上调试代码、修改ISP参数、查看AI推理日志,无需频繁连接电脑;:打造带交互的AI设备(如工业控制面板、智能显示器),鼠标操作菜单、键盘输入指令,体验媲美小型PC;:无网络场景下,通过键盘直接向AI设备录入数据、配置参数,适配野外监测、本地工控等场景。,自动识别、快速响应,完美适配交互控制、参数调试、数据输入等场景。

weixin_47446386的博客 145

基于R-CNN深度学习的石头剪刀布手势识别系统:数据集、模型和UI界面的完整实现

本项目的目标是开发一个基于R-CNN深度学习模型的手势识别系统,能够识别石头、剪刀、布三种手势,并通过UI界面让用户能够进行交互。数据集准备与标注:收集包含石头剪刀布手势的图像,并对其进行标注。深度学习模型构建与训练:采用R-CNN模型进行手势的识别和定位。UI界面设计:设计一个简洁的界面,用户可以上传手势图像并进行识别。R-CNN(Region Convolutional Neural Networks)是一个典型的目标检测模型。生成候选区域。

YOLO 876

学习笔记 20240805 Rust语言-Rust语言圣经-Box<T>

基于语言圣经的学习笔记之Box 堆对象分配,Rust 中的堆栈,Box的使用场景,Box内存布局,Box::leak

qq_51181223的博客 1218

vue2/3 - 详细实现内网使用离线百度地图功能,百度地图如何离线加载详细教程(内网部署及使用),在vue中无需网络离线使用百度地图相关功能,提供最新完整的瓦片资源下载及相关工具(示例代码,一键复制

vue,vue2,vue3,百度地图,离线使用百度地图,百度地图瓦片官方下载,vue内网使用百度地图离线无网络,断网情况下使用百度地图,vue离线百度地图教程,如何实现内网部署百度地图,无需联网离线使用,vue+ts实现离线百度地图 内网离线百度地图,如何在百度地图Vue项目中下载离线地图,百度离线地图加载不出来,百度地图离线使用不显示怎么办,怎么解决vue内网使用离线百度地图加载失败问题,vue实现离线地图+百度瓦片,vue引入百度离线地图,vue项目如何使用离线百度地图和自定义地图样式,百度离线地图的下

✅ 精选推荐文章 1万+

【RUST】智能指针Box<T>

最直接的智能指针是box,因为它实现了Deref trai,写法是Box<T>,它可以让数据存在堆上面,然后在栈上保持存引用,其它的功能Box暂时没有 在编译时,RUST需要知道一个类型占用空间的大小,无法知道的类型叫做recursive type,也就是递归类型 我们看看cons list这个数据结构 use crate::List::{Cons, Nil}; fn main() { let list = Cons(1, Cons(2, Cons(3, Nil))); } enum

屎蛋的铲屎官 804

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【Rust】——使用Box<T>指向堆上数据

🎯使用Box在堆上储存数据 🎯Box允许创建递归类型 🎃cons list 的更多内容 🎃计算非递归类型的大小 🎃使用Box给递归类型一个已知的大小

shsjssnn的博客 1059

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

再也不怕 Rust Box<T>!这篇文章让你一看就懂

在 C/C++ 里,指针只是单纯的内存地址,开发者需要手动管理内存(malloc/free 或 new/delete),很容易出 bug(悬垂指针、内存泄漏)。说个额外的,之前也做过一段iOS开发,古早版本oc的也是自己管理对象(alloc/release)。坏处是类似代码写的发抖,不然很容易有内存bug,好处是用户体验上一直无比丝滑。Rust 中的智能指针是一类结构体,行为像指针,但内部实现了额外的逻辑(比如自动释放、引用计数、共享所有权等)。Box<T>:堆分配,唯一所有权Rc<T>Arc<T>

2401_89221867的博客 709

【CXX】6.5 Box<T> — rust::Box<T>

如果 T 是不透明的 Rust 类型,则要求该 Rust 类型为 Sized,即在编译时已知大小。未来可能会引入对动态大小的不透明 Rust 类型的支持。以下程序使用 Box 将某些不透明的 Rust 状态的所有权传递给 C++,然后再传递回 Rust 回调函数。这是实现 FFI 异步函数的有用模式。Box 不支持 T 为不透明的 C++ 类型。对于在语言边界传递不透明 C++ 类型的所有权,应使用 UniquePtr 或 SharedPtr。

weixin_43219667的博客 448

Rust Box<T>, Rc<T>, RefCell<T>

Rc enables multiple owners of the same data; Box and RefCell have single owners. Box allows immutable or mutable borrows checked at compile time; Rc allows only immutable borrows checked at compile time; RefCell allow immutable and mutable borrows checke.

lilele12211104的专栏 400

Rust:智能指针 Box & Rc & Cow

讲解Rust的智能指针Box,Rc,Cow

博客网站 https://async-area.com 1188

Rust 堆内存指针 Box 详解

在 Rust 中,Box<T> 是最基础、最简洁的智能指针,核心作用是将数据从栈内存转移到堆内存,并通过独占所有权机制管理堆内存的分配与释放。与 Rust 中的裸指针 *const T、*mut T 不同,Box<T> 完全符合 Rust 的内存安全规则,无需手动管理内存,既保留了指针的灵活性,又规避了悬垂指针、内存泄漏等常见问题。

github_28443763的博客 585

Box:Rust中堆内存管理的基石

所有权语义:明确的数据所有权关系自动内存管理:自动释放分配的内存额外功能:提供引用计数、内部可变性等特性零成本抽象:编译时检查,无运行时开销为自定义类型实现Dereftrait:```rust// 自定义智能指针(BoximplMyBox// 实现Deref traitimpl&self.0// 实现DerefMut traitimpl// 自动解引用println!("长度: {}", my_box.len());// 自动调用derefprintln!

m0_46577795的博客 350

深入Rust:Box、Rc、Arc智能指针机制解析与实践指南

本文深入解析了Rust中三种核心智能指针(Box、Rc、Arc)的机制与实践应用。Box用于单一所有权的堆存储,解决递归类型、trait对象和大数据存储问题;Rc通过引用计数实现单线程下的共享只读数据,需注意循环引用风险;Arc是线程安全的Rc版本。文章从底层原理到典型场景,结合代码示例,帮助开发者合理选用智能指针以补充Rust所有权规则,同时规避常见内存管理陷阱。

chandfy的博客 1302

Rust从入门到实战系列一百六十七:使用 Box<T> 在堆上储存数据

在讨论 Box 的用例之前,让我们熟悉一下语法以及如何与储存在 Box 中的值进行交互。示例 15-1 展示了如何使用 box 在堆上储存一个 i32:文件名: src∕main.rsprintln!示例 15-1:使用 box 在堆上储存一个 i32 值这里定义了变量 b,其值是一个指向被分配在堆上的值 5 的 Box。这个程序会打印出 b = 5;在这个例子中,我们可以像数据是储存在栈上的那样访问 box 中的数据。正如任何拥有数据所有权的值那样,当像。

wanmeijuhao的博客 793

【Rust自学】15.1. 使用Box<T>智能指针来指向堆内存上的数据

`box<T>`可以被简单地理解为装箱,它是最简单的智能指针,允许你在堆内存上存储数据(而不是栈内存)。

A Rookie in San Domenico School 1372

Rust通过Box方式实现LinkedList

Rust基于 Box+Option组织的链表

JAN6055的博客 1269

Rust 2024 - 为 Box<[T]> 添加 IntoIterator 实现

摘要 Rust 1.80为Box<[T]>实现了IntoIterator,允许直接按值迭代boxed切片。在2024版前,boxed_slice.into_iter()仍会解引用为&[T]的迭代器;2024版后则直接调用IntoIterator返回值的迭代器。迁移可通过cargo fix --edition自动将.into_iter()替换为.iter()保留原有行为,lint会提示相关修改。

464
上一篇: Rust 学习笔记:使用自定义命令扩展 Cargo
下一篇: Rust 学习笔记:Deref trait
UestcXiye
博客等级 码龄8年 9028粉丝 1306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值