智慧指標

指標(pointer)是一個將變數儲存記憶體位址的通用概念。此位址參考或者說是「指向」一些其他資料。Rust 中最常見的指標種類就是第四章介紹的參考(reference)。參考以 & 符號作為指示並借用它們指向的數值。它們除了參考資料以外,沒有其他的特殊能力,也沒有任何額外開銷。

另一方面,智慧指標(Smart pointers)是個不只會有像是指標的行為,還會包含擁有的詮釋資料與能力。智慧指標的概念並不是 Rust 獨有的,智慧指標起源於 C++ 且也都存在於其他語言。Rust 在標準函式庫中有提供許多不同的智慧指標,不只能參考還具備更多的功能。為了探索各個概念,我們會來研究一些各種不同的智慧指標範例,包含參考計數(reference counting)智慧指標型別。此指標允許一個資料可以有多個擁有者,並追蹤擁有者的數量,當沒有任何擁有者時,就清除資料。

在 Rust 中,我們有所有權與借用的概念,所以參考與智慧指標之間還有一項差別:參考是只有借用資料的指標,但智慧指標在很多時候都擁有它們指向的資料。

雖然在前面的章節我們沒有這樣稱呼,但我們已經在本書中遇過一些智慧指標了,像是第八章的 StringVec<T>,雖然當時我們沒有稱呼它們為智慧指標。這些型別都算是智慧指標,因為它們都擁有一些記憶體並允許你操控它們。它們也有詮釋資料以及額外的能力或保障。像是 String 就會將容量儲存在詮釋資料中,並確保其資料永遠是有效的 UTF-8。

智慧指標通常都使用結構體實作。和一般結構體不同,智慧指標會實作 DerefDrop 特徵。Deref 特徵允許智慧指標結構體的實例表現的像是參考一樣,讓你可以寫出能用在參考與智慧指標的程式碼。Drop 特徵允許你自訂當智慧指標實例離開作用域時要執行的程式碼。在本章節我們會討論這兩個特徵並解釋為何它們對智慧指標很重要。

有鑑於智慧指標在 Rust 是個常用的通用設計模式,本章不會涵蓋每一個現有的智慧指標。許多函式庫也都會提供它們自己的智慧指標,你甚至能寫個你自己的。我們會提及標準函式庫中最常用到的智慧指標:

  • Box<T> 將數值配置到堆積上
  • Rc<T>, 參考計數型別來允許資料能有數個擁有者
  • 透過 RefCell<T> 來存取 Ref<T>RefMut<T> ,這是在執行時而非編譯時強制執行借用規則的型別

除此之外,我們還會涵蓋到內部可變性(interior mutability)模式,這讓不可變參考的型別能提供改變內部數值的 API。我們還會討論參考循環(reference cycles)為何會導致記憶體泄漏以及如何預防它們。

讓我們開始吧!