rust RefCell、Cell筆記

October 16, 2020

此文章記錄學習中的個人理解

文章在這

所有權、出借、移出

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了)。

playground



Written by Howard Chang , software engineer, programming lover, from Taiwan