[Rust] 理解 TreeNode 的子節點的 Option<Rc<RefCell<TreeNode>>>

R4 Cheng
3 min readNov 5, 2023

RefCell<T> 常搭配 Rc<T> 來擁有多個可變資料的擁有者

引言

由於最近開始研究 Rust ,於是開始嘗試用 Rust 寫 Leetcode 的題目 (我原本是習慣使用 JS/TS),然而,在寫 Tree 相關的題目的時候,看到子節點的 Type 是 Option<Rc<RefCell<TreeNode>>> 直接傻眼貓咪 =_=”,不明白為何包這麼多層。

pub struct TreeNode {
pub val: i32,
pub left: Option<Rc<RefCell<TreeNode>>>, // <= ????????
pub right: Option<Rc<RefCell<TreeNode>>>,
}

因此有了這一篇文章,以幫助自己釐清為什麼 TreeNode 要這樣定義。

在開始介紹 Type 之前先說結論:

結論

  • 使用 Option<T> 是因為 left child 和 right child 可能會是空值。
  • 使用 Rc<T> 表示多個父節點有機會共享同一個子節點。 (當然多數的 Leetcode 題目應該是用不到這個性質)
  • 使用 RefCell<T> 是因為即使父節點是不可變的,父節點上的子節點也可以被修改。

TreeNode 的 child 一共有3個 Type: RefCell<T>, Rc<T>Option<T> ,我們將由外而內進行剖析。

Option<T>

Rust 用 enum Option<T> 來實作空值 (null) 的概念,因此 Option<T> 表示一個數值可能有某個東西,或者什麼都沒有。

Rc<T>

aka. Reference Counting

Rc<T> 讓數個擁有者能共享相同資料。

性質

  • 只能在單一 thread 中使用
  • 慣例使用 Rc::clone 來拷貝 reference 。(因為僅增加參考計數,時間花費比深拷貝少很多)
  • 慣例透過 method Rc::strong_count 來印出參考計數

還有一個 method weak_count 在某些場景下有其功能。 Eg. 避免參考循環

為何需要 Rc<T>?

  1. 一個數值可能會有數個 owner
    Eg. 在 Graph 的資料結構中,數個邊可能都會指向同個節點,意味著該節點就被所有指向它的邊所擁有。直到沒有任何邊指向它,也就是沒有任何擁有者時它才會被清除。

RefCell<T>

RefCell<T> 會讓編譯器忽略,然後在 runtime 才檢查借用規則,使得不可變的參考內部的 type 能夠被修改

  • 內部可變性 (Interior Mutability)
  • 只能在單一 thread 中使用
  • 在 runtime 檢查參考: 編譯器會允許內部可變性,然後在 runtime 才檢查借用規則
  • borrow_mut: 取得 RefCell<T> 內的可變參考數值 T , return RefMut<T>
  • borrow: return Ref<T>
  • 模擬物件 (mock objects) 時,有時候會用到

為何需要 RefCell<T> ?

  1. 在編譯時期無法確定是否需要可變性
    Eg. 在 TreeNode 中,父節點可能是不可變的,但是父節點上的子節點可能是可變的。

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

R4 Cheng
R4 Cheng

Written by R4 Cheng

「0」が過去で「1」が未来「今」は何処にもない

No responses yet

Write a response