Box

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

  1. fn main() {
  2. let five = Box::new(5);
  3. println!("five: {}", *five);
  4. }

20.1. Box<T> - 图1

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

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

  1. #[derive(Debug)]
  2. enum List<T> {
  3. /// A non-empty list: first element and the rest of the list.
  4. Element(T, Box<List<T>>),
  5. /// An empty list.
  6. Nil,
  7. }
  8. fn main() {
  9. let list: List<i32> =
  10. List::Element(1, Box::new(List::Element(2, Box::new(List::Nil))));
  11. println!("{list:?}");
  12. }

20.1. Box<T> - 图2

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 be able to compute a fixed size for the struct in memory (the List would be of infinite size).

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

  • Remove the Box in the List definition and show the compiler error. We get the message “recursive without indirection”, because for data recursion, we have to use indirection, a Box or reference of some kind, instead of storing the value directly.

探索更多

小众优化

Though Box looks like std::unique_ptr in C++, it cannot be empty/null. This makes Box one of the types that allow the compiler to optimize storage of some enums.

For example, Option<Box<T>> has the same size, as just Box<T>, because compiler uses NULL-value to discriminate variants instead of using explicit tag (“Null Pointer Optimization”):

  1. use std::mem::size_of_val;
  2. struct Item(String);
  3. fn main() {
  4. let just_box: Box<Item> = Box::new(Item("Just box".into()));
  5. let optional_box: Option<Box<Item>> =
  6. Some(Box::new(Item("Optional box".into())));
  7. let none: Option<Box<Item>> = None;
  8. assert_eq!(size_of_val(&just_box), size_of_val(&optional_box));
  9. assert_eq!(size_of_val(&just_box), size_of_val(&none));
  10. println!("Size of just_box: {}", size_of_val(&just_box));
  11. println!("Size of optional_box: {}", size_of_val(&optional_box));
  12. println!("Size of none: {}", size_of_val(&none));
  13. }