Rust中的Rc

2023-03-07  本文已影响0人  天之見證

特点

  1. 单线程的引用计数

  2. 不可变引用

  3. 非线程安全,线程安全请使用Arc

循环引用问题

仅仅使用Rc会遇到循环引用的问题,导致指针没法被释放掉,此时可以通过Weak来打破这种引用。如下图所示:

图片.png

Weak

Weak可以看作是一种特殊的Rc,它引用对象的时候并不会增加计数,也不保证它对应的对象一直有效。主要用在:

  1. 保有一个Rc管理的空间的临时引用,但并不会防止其被释放

  2. 循环引用

没有自解引用

Rc,Weak相互转换

use std::rc::Rc;
use std::ptr;

let strong = Rc::new("hello".to_owned());
let weak = Rc::downgrade(&strong);

自解引用

Rc<T>是自动解引用的,所以可以直接使用T的方法。所以一般调用Rc自身的方法的时候,经常采用类名调用的方式:

use std::rc::Rc;
let rc = Rc::new(());
let rc2 = Rc::clone(&rc);
let rc3 = rc.clone();  // 这种调用方式也是可以的

示例

场景一

一个Owner有一堆小玩意儿,我们先让我们的小玩意儿指向它们的Owner,但是这种拥有又不是唯一的,即一个Owner只有1个小玩意儿,一个Owner有多个小玩意儿,此时这些小玩意儿就需要共享这个Owner

use std::rc::Rc;

struct Owner {
    name: String,
    // ...other fields
}

struct Gadget {
    id: i32,
    owner: Rc<Owner>,
    // ...other fields
}

fn main() {
    // Create a reference-counted `Owner`.
    let gadget_owner: Rc<Owner> = Rc::new(
        Owner {
            name: "Gadget Man".to_string(),
        }
    );

    // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc<Owner>`
    // gives us a new pointer to the same `Owner` allocation, incrementing
    // the reference count in the process.
    let gadget1 = Gadget {
        id: 1,
        owner: Rc::clone(&gadget_owner),
    };
    let gadget2 = Gadget {
        id: 2,
        owner: Rc::clone(&gadget_owner),
    };

    // Dispose of our local variable `gadget_owner`.
    drop(gadget_owner);

    // Despite dropping `gadget_owner`, we're still able to print out the name
    // of the `Owner` of the `Gadget`s. This is because we've only dropped a
    // single `Rc<Owner>`, not the `Owner` it points to. As long as there are
    // other `Rc<Owner>` pointing at the same `Owner` allocation, it will remain
    // live. The field projection `gadget1.owner.name` works because
    // `Rc<Owner>` automatically dereferences to `Owner`.
    println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
    println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);

    // At the end of the function, `gadget1` and `gadget2` are destroyed, and
    // with them the last counted references to our `Owner`. Gadget Man now
    // gets destroyed as well.
}

场景二

在场景一的基础之上,我们还需要可以从Owner获取它的小玩意儿

这里其实还隐含着需要修改Owner对应的数据

gadget类型做如下解释:

图片.png

由于OwnerRc包裹了,所以gadgets也要用RefCell包裹,不然没法进行修改。

因为我们只能获得一个Owner的不可变引用

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;

struct Owner {
    name: String,
    gadgets: RefCell<Vec<Weak<Gadget>>>,
    // ...other fields
}

struct Gadget {
    id: i32,
    owner: Rc<Owner>,
    // ...other fields
}

fn main() {
    // Create a reference-counted `Owner`. Note that we've put the `Owner`'s
    // vector of `Gadget`s inside a `RefCell` so that we can mutate it through
    // a shared reference.
    let gadget_owner: Rc<Owner> = Rc::new(
        Owner {
            name: "Gadget Man".to_string(),
            gadgets: RefCell::new(vec![]),
        }
    );

    // Create `Gadget`s belonging to `gadget_owner`, as before.
    let gadget1 = Rc::new(
        Gadget {
            id: 1,
            owner: Rc::clone(&gadget_owner),
        }
    );
    let gadget2 = Rc::new(
        Gadget {
            id: 2,
            owner: Rc::clone(&gadget_owner),
        }
    );

    // Add the `Gadget`s to their `Owner`.
    {
        let mut gadgets = gadget_owner.gadgets.borrow_mut();
        gadgets.push(Rc::downgrade(&gadget1));
        gadgets.push(Rc::downgrade(&gadget2));

        // `RefCell` dynamic borrow ends here.
    }

    // Iterate over our `Gadget`s, printing their details out.
    for gadget_weak in gadget_owner.gadgets.borrow().iter() {

        // `gadget_weak` is a `Weak<Gadget>`. Since `Weak` pointers can't
        // guarantee the allocation still exists, we need to call
        // `upgrade`, which returns an `Option<Rc<Gadget>>`.
        //
        // In this case we know the allocation still exists, so we simply
        // `unwrap` the `Option`. In a more complicated program, you might
        // need graceful error handling for a `None` result.

        let gadget = gadget_weak.upgrade().unwrap();
        println!("Gadget {} owned by {}", gadget.id, gadget.owner.name);
    }

    // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2`
    // are destroyed. There are now no strong (`Rc`) pointers to the
    // gadgets, so they are destroyed. This zeroes the reference count on
    // Gadget Man, so he gets destroyed as well.
}
上一篇下一篇

猜你喜欢

热点阅读