如何在Rust的结构体中使用循环依赖?

42fyovps  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(157)

我有两个相互依赖的结构体,在C++中我会用指针来做这个,我正在尝试在Rust中怎么做,到目前为止我试过用Box和Rc,我想既然Rc是一个引用计数器,它应该能处理这个,但是它给了我一个错误。
下面是一个简单的代码示例:

struct A {
    b : Rc<B>
}

struct B {
    a : Option<Rc<A>>
}

fn main() {

    let mut b = B {
        a : None
    };

    let a = A {
        b: Rc::new(b)
    };

    b.a = Some(Rc::new(a));

}

下面是我从中得到的错误:

20 |     let mut b = B {
   |         ----- move occurs because `b` has type `B`, which does not implement the `Copy` trait
...
25 |         b: Rc::new(b)
   |                    - value moved here
...
28 |     b.a = Some(Rc::new(a));
   |     ^^^ value partially assigned here after move

在Rust中建立这种关系的正确方法是什么?

unftdfkk

unftdfkk1#

你不应该对一个对象使用两次Rc::new。正确的方法是使用一次Rc::new,然后根据需要克隆它。更重要的是,为了将b变异到Rc之后,你应该将它与RefCell组合。

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

struct A {
    b: Rc<B>,
}

struct B {
    a: RefCell<Option<Rc<A>>>,
}

fn main() {
    let b = Rc::new(B {
        a: RefCell::new(None),
    });
    let a = Rc::new(A { b: b.clone() });

    *b.a.borrow_mut() = Some(a.clone());

    assert!(b.a.borrow().is_some());
}

但是即使你这样做了,你仍然会制造内存泄漏,这很糟糕,一个更好的方法是使用WeakRc::new_cyclic来制造循环。

use std::rc::{Rc, Weak};

struct A {
    b: Rc<B>,
}

struct B {
    a: Weak<A>,
}

fn main() {
    let a: Rc<A> = Rc::new_cyclic(|a| A {
        b: Rc::new(B { a: a.clone() }),
    });
    let b: Rc<B> = a.b.clone();
}

这避免了使用单元和内存泄漏。

bwleehnv

bwleehnv2#

这是编译(这是单线程示例)

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

// make a cycle: struct A owning struct B and struct B owning struct A
struct A {
    b :  Rc<RefCell<B>>
}

struct B {
    a :  Option<Rc<RefCell<A>>>
}

fn main() {

    // init b with None
    let b = Rc::new(RefCell::new(B { a: None }));

    // init a with b
    let a = Rc::new(RefCell::new(A { b: Rc::clone(&b) }));

    // set b.a to a
    b.borrow_mut().a = Some(Rc::clone(&a));
}

你用Rc来拥有多重所有权,这样你就可以把b移到a,然后仍然把它命名为b,甚至尝试改变它。
Rc是只读的,所以使用RefCell可以隐藏更改内容的事实。
在Rust book https://doc.rust-lang.org/book/ch15-06-reference-cycles.html中还有另一个循环的例子

相关问题