9.1 Box<T>:堆分配
听
在 Rust 中,大多数值默认分配在栈上,具有确定的大小和生命周期。然而,某些场景需要将数据存储在堆(heap)上,例如:
- 数据大小在编译时未知(如递归数据结构);
- 需要将大对象的所有权转移而不复制;
- 实现 trait 对象(如
Box<dyn Trait>)。
Box<T> 是 Rust 提供的最基础的智能指针类型,用于在堆上分配值,并在离开作用域时自动释放内存。
基本用法
创建一个 Box 很简单:
let x = 5;
let boxed_x = Box::new(x);
println!("boxed_x = {}", boxed_x); // 输出: 5
这里,整数 5 被分配在堆上,boxed_x 是一个指向该堆内存的指针。尽管如此,你可以像使用普通值一样使用 boxed_x,因为 Box<T> 实现了 Deref trait,支持自动解引用。
用于递归类型
Rust 要求所有类型在编译时具有已知大小。对于递归结构(如链表、树),直接定义会导致无限大小:
// ❌ 编译错误:recursive type has infinite size
enum List {
Cons(i32, List),
Nil,
}
通过将递归部分放入 Box,可以打破无限嵌套,因为 Box 本身大小固定(指针大小):
enum List {
Cons(i32, Box<List>),
Nil,
}
let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
现在,List 的大小是固定的:一个枚举标签加上一个指针。
与 Deref 的集成
Box<T> 实现了 Deref<Target = T>,因此在需要 &T 的上下文中,&Box<T> 会自动转换为 &T:
fn print_value(value: &i32) {
println!("{}", value);
}
let b = Box::new(42);
print_value(&b); // 自动解引用,无需写 *b
同样,Box<T> 也实现了 Drop,当离开作用域时,会自动释放堆内存,无需手动管理。
其他用途
- 抽象所有权:函数返回
Box<dyn Trait>可隐藏具体类型; - 减少栈占用:将大结构体放入
Box可避免栈溢出; - 互操作性:与 C 接口交互时,有时需显式堆分配。
性能考量
Box<T> 的开销极小:
- 分配/释放涉及一次堆操作;
- 访问数据需一次指针间接寻址;
- 无运行时借用检查或引用计数。
因此,它常被用作“零成本”堆分配工具。
小结
Box<T> 是 Rust 中最简单的智能指针,主要用于将数据移至堆上,解决类型大小未知或所有权转移问题。它无缝集成于 Rust 的所有权系统,自动管理内存,且性能开销可控。虽然功能单一,但它是构建更复杂数据结构(如链表、树)和实现动态分发的基础组件。理解 Box 的作用,是掌握 Rust 内存管理的第一步。
#Rust 入门教程
分享于 1 周前
上一篇:第九章:智能指针与内存管理
下一篇:9.2 Rc<T> 与 Arc<T>