Box<T>

Box は、ヒープ上のデータへの所有ポインタです。

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

Box<T>Deref<Target = T> を実装しているため、Box<T> に対して T のメソッドを直接呼び出すことができます。

Recursive data types or data types with dynamic sizes cannot be stored inline without a pointer indirection. Box accomplishes that indirection:

#[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:?}");
}
StackHeaplistElement1Element2Nil
This slide should take about 8 minutes.
  • Box は C++ の std::unique_ptr と似ていますが、null ではないことが保証されている点が異なります。

  • Box は次のような場合に役立ちます。

    • have a type whose size can't be known at compile time, but the Rust compiler wants to know an exact size.
    • 大量のデータの所有権をムーブしたい場合。スタック上の大量のデータがコピーされないようにするには、代わりにBox によりヒープ上にデータを格納し、ポインタのみが移動されるようにします。
  • 仮にBox を使用せずに ListList に直接埋め込もうとすると、コンパイラはメモリ内の構造体の固定サイズを計算しようとしません(List は無限サイズになります)。

  • 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 (the "niche optimization").