Rust 程式設計視訊教程(進階)——015_1 引用迴圈

linghuyichong發表於2020-02-05

頭條地址:https://www.ixigua.com/i677586170644791348...
B站地址:https://www.bilibili.com/video/av81202308/

github地址:https://github.com/anonymousGiga/learn_rus...

引用迴圈,讓兩個list指向彼此,例子程式碼如下:

use std::rc::Rc;
use std::cell::RefCell;
use crate::List::{Cons, Nil};

#[derive(Debug)]
enum List {
    Cons(i32, RefCell<Rc<List>>),
    Nil,
}

impl List {
    fn tail(&self) -> Option<&RefCell<Rc<List>>> {
        match self {
            Cons(_, item) => Some(item),
            Nil => None,
        }
    }
}

fn main() {
    let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));

    println!("a initial rc count = {}", Rc::strong_count(&a));
    println!("a next item = {:?}", a.tail());

    let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));

    println!("a rc count after b creation = {}", Rc::strong_count(&a));
    println!("b initial rc count = {}", Rc::strong_count(&b));
    println!("b next item = {:?}", b.tail());

    if let Some(link) = a.tail() {
        *link.borrow_mut() = Rc::clone(&b);    //將a修改為指向b
    }

    println!("b rc count after changing a = {}", Rc::strong_count(&b)); //輸出引用計數,為2
    println!("a rc count after changing a = {}", Rc::strong_count(&a)); //輸出引用計數,為2

    //下面的呼叫將出錯,因為上面已經制造了迴圈引用,編譯器無法找到tail
    // println!("a next item = {:?}", a.tail());
}

Rust

說明:
(1)在main函式的結尾,Rust會嘗試丟棄b,這會使a和b中Rc例項的引用計數減為1.但是,因為a仍然引用b中的Rc,因此Rc的計數是1而不是0,所以Rc在堆上的記憶體不會被丟棄,從而造成記憶體洩露。

(2)在上面的例子中,其相互引用關係如上圖所示,如果列印a.tail(),那麼就會在上面的迴圈中一直查詢(符合(_, item)的情況),但是永遠沒有結束(因為是個迴圈,永遠找不到匹配的情況),最終會造成棧溢位。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

令狐一衝

相關文章