智慧指標相關概念
指標:是一個包含記憶體地址的變數(指向其它資料)。Rust中最常見的指標是”引用”。 引用(借用):
使用&
借用它指向的值
沒有其餘開銷
是最常見的指標型別
智慧指標
智慧指標是這樣一些資料結構:
行為和指標相似
有額外的元資料和功能
引用計數(reference counting)智慧指標型別
透過記錄所有者的數量,使一份資料被多個所有者同時持有
並在沒有任何所有者時自動清理資料
引用和智慧指標的區別
引用:只是借用資料
智慧指標:很多時候都擁有它所指向的資料
智慧指標的例子
例如String和Vec
都擁有一片記憶體區域,且允許使用者對其操作
擁有元資料(例如容量等)
提供額外的功能或保障(String保障其資料是合法的UTF-8編碼)
智慧指標的實現
智慧指標通常使用struct實現,並且實現了:
Deref trait
Drop trait
Deref trait:允許智慧指標struct的例項像引用一樣實現 Drop:允許我們自定義當智慧指標例項走出作用域時執行的程式碼
標準庫中常見的智慧指標:
Box
Rc
Ref
此外:
內部可變模式(interior mutability pattern):不可變型別暴露出可修改其內部值的API
引用迴圈(reference cycles):它們如何洩露記憶體,以及如何防止其發生
使用Box
Box
允許我們在堆上儲存資料(而不是棧上)
棧上存的是指向堆記憶體資料的指標
沒有效能開銷
沒有其它額外的功能
實現了Deref和Drop trait
Box
在編譯時,某型別的大小無法確定。但使用該型別時,上下文卻需要知道它的確切大小
當我們有大量資料,想移交所有權,但需要確保在操作資料時不會被複制
使用某個值時,我們只關心它是否實現了特定的trait,而不關心它的具體型別
使用Box
fn main() { let a = Box::new(6); println!(“a = {}”, a);}
當a走出作用域時,它在堆記憶體上的資料和棧上的指標都會被釋放。
Box
在編譯時,Rust需要知道一個型別所佔的空間大小。而遞迴型別(如圖所示)的大小無法在編譯時確定。
但是Box型別的大小確定,所以在遞迴型別中使用Box就可以解決上述問題。 這種型別類似於函式式語言中的Cons List。
關於Cons List
Cons List是來自Lisp語言的一種資料結構,其中的每個成員都由兩個元素組成:
當前項的值,例如圖上的i32
下一個元素,是它本身
Cons List裡最後一個成員只包含一個Nil值,沒有下一個元素。
但是在Rust中,Cons List不是常用的集合,通常情況下,Vec
使用Box來獲得確定大小的遞迴型別
enum List { Cons(i32, Box), Nil,}fn main() { let list = List::Cons( 1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))), );}
Box
只提供了“間接”儲存和堆記憶體分配的功能
沒有提供其它額外的功能
沒有效能開銷
適用於需要“間接”儲存的場景,如Cons List
實現了Deref和Drop兩個trait