让两个结构相互引用 - 生锈

having two struct reference each other - rust

我对 Rust 编程还很陌生,我正在尝试将我在 js 中的代码转换为 Rust。

简单的概念如下:

fn main() {
    let mut ds=DataSource::new();
    let mut pp =Processor::new(&mut ds);
}

struct DataSource {
    st2r: Option<&Processor>,
}

struct Processor {
    st1r: &DataSource,
}

impl DataSource {
    pub fn new() -> Self {
        DataSource {
            st2r: None,
        }
    }
}

impl Processor {
    pub fn new(ds: &mut DataSource) -> Self {
        let pp = Processor {
            st1r: ds,
        };
        ds.st2r = Some(&pp);
        pp
    }
}

如您所见,我的系统中有两个相互连接的主要模块,我需要每个模块在另一个模块中的引用。

好吧,这段代码当然会抱怨生命周期之类的东西。所以我开始像疯子一样到处乱扔生命周期说明符,即便如此,它仍然抱怨说在“Processor::new”中我不能 return 借用的东西。合法的。但我找不到任何解决方案!无论我如何尝试处理彼此的引用,它都以这个借用错误结束。

那么,有人可以针对这种情况指出解决方案吗?我的应用程序的结构在 Rust 中是否无效,我应该以其他方式进行吗?还是我没有经验的头脑找不到这个技巧?

谢谢。

您尝试做的事情不能用引用和生命周期来表达,因为:

  • DataSource必须比Processor活得长,这样pp.st1r才能保证有效,
  • Processor 必须比 DataSource 活得更长,这样才能保证 ds.st2r 有效。您可能会认为,由于 ds.st2r 是一个 Option,并且由于 None 变体不包含引用,因此允许 DataSource 具有 Nonest2r 比任何 Processor 都长,但不幸的是,编译器在编译时无法知道 st2r 是否包含 Some 值,因此必须假设它包含。

您的问题因您需要对 DataSource 可变 引用而变得更加复杂,以便您可以一次设置其 st2r 字段当你在 Processor 中也有一个不可变的未完成引用时,Rust 不允许。

您可以通过使用 Rc (for dynamic lifetime tracking) and RefCell(用于动态可变性跟踪)切换到动态生命周期和可变性跟踪来使您的代码正常工作:

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

fn main() {
    let ds = Rc::new (RefCell::new (DataSource::new()));
    let pp = Processor::new (Rc::clone (&ds));
}

struct DataSource {
    st2r: Weak<Processor>,
}

struct Processor {
    st1r: Rc<RefCell<DataSource>>,
}

impl DataSource {
    pub fn new() -> Self {
        DataSource {
            st2r: Weak::new(),
        }
    }
}

impl Processor {
    pub fn new(ds: Rc::<RefCell::<DataSource>>) -> Rc<Self> {
        let pp = Rc::new (Processor {
            st1r: ds,
        });
        pp.st1r.borrow_mut().st2r = Rc::downgrade (&pp);
        pp
    }
}

Playground

请注意,我已将您的 Option<&Processor> 替换为 Weak<Processor>。可以使用 Option<Rc<Processor>>,但如果您在没有先将 st2r 设置为 None 的情况下删除对 DataSource 的所有引用,这将有内存泄漏的风险。 Weak<Processor> 的行为或多或少类似于 Option<Rc<Processor>>,当所有其他引用被删除时,它会自动设置为 None,确保内存将被正确释放。