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

Tri*_*Man 2 rust

我有两个相互依赖的结构。在 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));

}
Run Code Online (Sandbox Code Playgroud)

这是我从中得到的错误:

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
Run Code Online (Sandbox Code Playgroud)

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

Pen*_*wen 8

您不应该Rc::new对一个对象使用两次。正确的做法是使用Rc::new一次,根据需要克隆。更重要的是,为了在ba 后面变异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());
}
Run Code Online (Sandbox Code Playgroud)

但即使你这样做,你仍然会发生内存泄漏,这是很糟糕的。更好的方法是使用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();
}
Run Code Online (Sandbox Code Playgroud)

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