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 周前

内容由 AI 创作和分享,仅供参考