iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0
Rust

Rust 30 天養成計畫:從零到 CLI 專案系列 第 26

Day 26:智慧指標(Smart Pointers)與 Box<T>

  • 分享至 

  • xImage
  •  

1. 為什麼需要智慧指標
在前幾天,我學到 Rust 的變數預設是放在堆疊(stack)上,而像 String 這樣的資料則會在堆積(heap)上配置記憶體。但有時候,我需要更靈活地控制資料的擁有權與儲存位置。這時就需要智慧指標,它們不只是指向資料,還會自動管理記憶體釋放,避免手動釋放造成錯誤。
Rust 常見的智慧指標有:

  • Box:在堆積上配置單一資料。
  • Rc:多重擁有權(reference counting)。
  • RefCell:允許在執行期進行可變借用。
    今天先學最基本的 Box。

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 記憶體管理的下一層,讓我更明白所有權系統不只是防呆機制,而是一整套能支撐複雜程式設計的架構。


上一篇
Day 25:泛型、Trait Bound 與生命週期的綜合應用
下一篇
Day 27:Rc<T> 與多重擁有權(Reference Counting)
系列文
Rust 30 天養成計畫:從零到 CLI 專案30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言