Box<T>

Box 是指向堆上数据的自有指针:

fn main() {
    let five = Box::new(5);
    println!("five: {}", *five);
}
5StackHeapfive

Box<T> 会实现 Deref<Target = T>,这意味着您可以直接在 Box<T> 上通过 T 调用相应方法

递归数据类型或具有动态大小的数据类型需要使用 Box

#[derive(Debug)]
enum List<T> {
    /// A non-empty list: first element and the rest of the list.
    Element(T, Box<List<T>>),
    /// An empty list.
    Nil,
}

fn main() {
    let list: List<i32> =
        List::Element(1, Box::new(List::Element(2, Box::new(List::Nil))));
    println!("{list:?}");
}
StackHeaplistElement1Element2Nil
This slide should take about 8 minutes.
  • Box is like std::unique_ptr in C++, except that it’s guaranteed to be not null.

  • 在以下情况下,Box 可能会很实用:

    • 在编译时间遇到无法知晓大小的类型,但 Rust 编译器需要知道确切大小。
    • 想要转让大量数据的所有权。为避免在堆栈上复制大量数据,请改为将数据存储在 Box 中的堆上,以便仅移动指针。
  • If Box was not used and we attempted to embed a List directly into the List, the compiler would not compute a fixed size of the struct in memory (List would be of infinite size).

  • Box 大小与一般指针相同,并且只会指向堆中的下一个 List 元素, 因此可以解决这个问题。

  • Box 从 List 定义中移除后,画面上会显示编译器错误。如果您看到“Recursive with indirection”错误消息,这是在提示您使用 Box 或其他类型的引用,而不是直接储存值。

探索更多

小众优化

#[derive(Debug)]
enum List<T> {
    Element(T, Box<List<T>>),
    Nil,
}

fn main() {
    let list: List<i32> =
        List::Element(1, Box::new(List::Element(2, Box::new(List::Nil))));
    println!("{list:?}");
}

Box 不得为空,因此指针始终有效且非 null。这样, 编译器就可以优化内存布局:

StackHeaplistElement1Element2