Box

Box 是 Rust 中非常方便的型別。當你使用 Box 時,你可以把型別放在堆積上而不是堆疊上。要做出新的 Box,只要用 Box::new() 並把元素放在裡面即可。

fn just_takes_a_variable<T>(item: T) {} // 接受任何東西並丟棄.

fn main() {
    let my_number = 1; // 這是 i32
    just_takes_a_variable(my_number);
    just_takes_a_variable(my_number); // 使用這個函式兩次也沒問題, 因為它是 Copy

    let my_box = Box::new(1); // 這是 Box<i32>
    just_takes_a_variable(my_box.clone()); // 沒有 .clone() 時第二個函式會造成錯誤
    just_takes_a_variable(my_box); // 因為 Box 不是 Copy
}

一開始很難想像能在哪裡使用它,但你會在 Rust 中經常使用它。你記得 & 被用在 str 是因為編譯器不知道 str 的大小:它可以是任何長度。但是用 & 的參考永遠是相同的長度,所以編譯器可以使用它。Box 也類似。另外你也可以在 Box 上使用 * 來獲得值,就像使用 & 一樣:

fn main() {
    let my_box = Box::new(1); // 這是 Box<i32>
    let an_integer = *my_box; // 這是 i32
    println!("{:?}", my_box);
    println!("{:?}", an_integer);
}

這就是為什麼 Box 被稱為"智慧指標(smart pointer)"的原因,因為它就像 & 的參考(一種指標),但可以做更多的事情。

你也可以使用 Box 來建立裡面有相同結構的結構體。這些是被稱為 遞迴 的結構,這意味著在 Struct A 裡面也許是另一個 Struct A,有時你可以使用 Box 來建立連結串列,儘管這在 Rust 中並不十分流行。但如果你想建立遞迴結構體,你可以使用 Box。如果你試著不用 Box 會發生什麼:

#![allow(unused)]
fn main() {
struct List {
    item: Option<List>, // ⚠️
}
}

這個簡單的 List 有一個元素,可能是個 Some<List> (另一個列表),也可能是 None。因為你可以選擇 None,所以它不會永遠遞迴。但是編譯器還是不知道大小:

error[E0072]: recursive type `List` has infinite size
  --> src\main.rs:16:1
   |
16 | struct List {
   | ^^^^^^^^^^^ recursive type has infinite size
17 |     item: Option<List>,
   |     ------------------ recursive without indirection
   |
   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable

你可以看到它甚至建議嘗試 Box。所以讓我們用 Box 把 List 包起來:

struct List {
    item: Option<Box<List>>,
}
fn main() {}

現在編譯器就可以用 List 了,因為所有的東西都在 Box 後面,而且它知道 Box 的大小。那麼一個非常簡單的列表可能像這樣:

struct List {
    item: Option<Box<List>>,
}

impl List {
    fn new() -> List {
        List {
            item: Some(Box::new(List { item: None })),
        }
    }
}

fn main() {
    let mut my_list = List::new();
}

即使沒有資料也有點複雜,Rust 並不怎麼常用這種類型的模式(pattern)。這是因為 Rust 如你所知的對借用(borrowing)和所有權(ownership)有嚴格的規定。但如果你想開始寫這樣的列表(連結串列)時,Box 能幫上忙。

Box 還可以讓你對它使用 std::mem::drop,因為它放在堆積上。這有時候會很方便。