此文章記錄學習中的個人理解
所有權、出借、移出
rust 特別的地方就是有所有權的概念。透過所有權的規則檢查,可以很有效率的管控記憶體的使用;並且可以檢查是否有 dangling refernence的風險。
雖然在寫程式的時候非常麻煩,但是程式run起來以後,可以基本保證不會有 runtime error的情形發生。習慣以後開發會很有效率。
同時所有權的觀念也可以融入到打程式的思考當中。
參照? 指標?
在C++中,其實也有 把 Pointer 跟 Reference 的概念分開來。
如果你跟我一樣,只熟悉 C,不熟悉 C++ 的話:
指標的概念就是「指向記憶體的某個位置」。因此,rust中參照也可以視為一個指標,但是它是靜態的(const),不能改變指標指向的位置。
但是,因為rust多了所有權的概念,而且參照的操作方式也跟c的指標不太一樣,而且必須尊守參照規則。
(例如:在c當中,要操作參照位置的變數一定要透過指標 derefrence(*);rust的參照則不需要)
因此,在 rust 看到 函式傳入參照時,必須以 借出(borrow)來思考,不能使用c的指標思考。
C++ 也有參照的概念,跟rust就比較相似,不過C++並沒有 借出的規則要尊守。
出借的規則
先不提lifetime,出借主要兩個規則:
- 在任何情況下,可以同時借出多個inmutable 參照,但是只能借出一個 mutable 參照。
- 在任何時間點下,參照都必須是合法的。
智慧指標
智慧指標是多了一些能力的指標。
在rust中,如果智慧指標有實作 Deref trait,就基本可以把它當成一般參照使用了。
它其實不是rust的特別概念,在C++ 也有這個概念。
Cell / RefCell
上面提到,參照的規則,同時只能有一個 mutable 參照。如果有多個參照需要修改,可以使用Cell。
Cell中的型態需要實作 Copy trait
Cell 跟 Cow 其實只差一點。Cell 是「取用時復製」,Cow是「寫入時復製」。
RefCell 則是可以使用 boroow (reference)的方式取得 內部的值; 它透過RefCell使用rust 的 lifetime機制實作動態檢查。
它可以動態檢查 borrow 的規則,將borrow的規則延遲到 runtime。
以下:
use std::cell::RefCell;
fn main() {
let a = RefCell::new(5);
let b = a.borrow_mut();
let c = a.borrow_mut();
println!("{}", c);
}的確將borrow 放到運行時檢查。
Rc
Rc 是 reference counting (參照技術)的意思。它是一個記憶體管理的技術。主要概念是,當沒有參照時就釋放記憶體。
Rc::clone 是 clone Rc 這個 pointer,不是Rc 內的值。
文章提到的 linked list,使用RefCell 是為了動態檢查 borrow規則;而使用Rc可以讓多個變數可以同時參照同一個位置(這樣就可以實作雙向linked list了)。