1. 為什麼需要智慧指標
在前幾天,我學到 Rust 的變數預設是放在堆疊(stack)上,而像 String 這樣的資料則會在堆積(heap)上配置記憶體。但有時候,我需要更靈活地控制資料的擁有權與儲存位置。這時就需要智慧指標,它們不只是指向資料,還會自動管理記憶體釋放,避免手動釋放造成錯誤。
Rust 常見的智慧指標有:
2. 使用 Box 儲存堆積資料
Box 允許把一個值放在 heap 上,並在 stack 上保留一個指向它的指標。
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
輸出:
b = 5
這段程式中,Box::new(5) 會在 heap 上配置一個 i32,b 則是指向該值的智慧指標,當 b 離開作用域時,Box 會自動釋放記憶體。
3. Box 的典型用途:遞迴型別(Recursive Types)
Rust 不允許直接定義遞迴型別(會導致大小無法確定),但可以用 Box 來包裝成固定大小。
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
println!("Linked list created successfully!");
}
輸出:
Linked list created successfully!
這裡的 Box 讓編譯器知道每個節點的大小是固定的(因為 Box 只是指標)。
4. Box 釋放記憶體的時機
Box 會在離開作用域時自動呼叫 drop() 釋放記憶體。
fn main() {
{
let b = Box::new(10);
println!("b = {}", b);
} // 離開作用域後,Box 自動釋放
println!("Box dropped!");
}
輸出:
b = 10
Box dropped!
這代表不需要手動釋放記憶體,也不會有懸垂指標(dangling pointer)問題。
5. Box 的 Deref 特性
Box 會自動實作 Deref,所以可以像一般變數一樣使用 * 或直接取值。
fn main() {
let x = 5;
let y = Box::new(x);
println!("x = {}, y = {}", x, *y); // *y 取出 Box 內部的值
}
輸出:
x = 5, y = 5
因為 Deref 的存在,許多情況下甚至不需要手動寫 *,Rust 會自動進行解參考。
6. 學習心得與補充
Box 讓我能把資料放到 heap 上而不用擔心釋放問題,尤其在處理像遞迴結構這種需要「間接儲存」的情況時非常實用。我覺得這一天的學習就像是開啟了 Rust 記憶體管理的下一層,讓我更明白所有權系統不只是防呆機制,而是一整套能支撐複雜程式設計的架構。