美文网首页
Rust中的Rc

Rust中的Rc

作者: 天之見證 | 来源:发表于2023-03-07 18:36 被阅读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.
    }
    

    相关文章

      网友评论

          本文标题:Rust中的Rc

          本文链接:https://www.haomeiwen.com/subject/imvildtx.html