在Rust中引用包含的结构体(并调用其方法)

6
编辑注:此代码示例来自 Rust 1.0 之前的版本,不是符合语法的 Rust 1.0 代码。更新后的代码会产生不同的错误,但答案仍包含有价值的信息。
我正在尝试在 Rust 中编写一个容器结构,其中它的元素还存储对包含容器的引用,以便它们可以调用容器上的方法。据我所知,我需要通过 Rc> 来实现这一点。这正确吗?
到目前为止,我已经有了类似以下的东西:
struct Container {
  elems: ~[~Element]
}

impl Container {
  pub fn poke(&mut self) {
    println!("Got poked.");
  }
}

struct Element {
  datum: int,
  container: Weak<RefCell<Container>>
}

impl Element {
  pub fn poke_container(&mut self) {
    let c1 = self.container.upgrade().unwrap(); // Option<Rc>
    let mut c2 = c1.borrow().borrow_mut(); // &RefCell
    c2.get().poke();
//    self.container.upgrade().unwrap().borrow().borrow_mut().get().poke();
//    -> Error: Borrowed value does not live long enough * 2
  }
}

fn main() {
  let container = Rc::new(RefCell::new(Container{ elems: ~[] }));
  let mut elem1 = Element{ datum: 1, container: container.downgrade() };
  let mut elem2 = Element{ datum: 2, container: container.downgrade() };
  elem1.poke_container();
}

我感觉我在这里还少了些什么。在poke_container中访问Rc<RefCell<T>>的内容真的这么困难吗?或者我是在错误地解决问题吗?

最后,假设方法正确,如果我为Container编写一个add方法,以便它可以填充Element中的container字段(假设我将该字段更改为Option<Rc<RefCell<T>>>),我不知道如何从&mut self创建另一个Rc


2
顺便说一句,完全没有必要使用~[~Element]代替~[Element] - Vladimir Matveev
@Vladimir 确实,谢谢,但在我的实际代码中 Element 是一个 trait,所以我认为在这种情况下不能省略 ~ - Kolja
1
是的,你说得对,在那种情况下你需要使用~。至于问题,我不知道如何简化访问Rc盒子内容的方式。现在就是这样工作的。希望当真正的Gc到来时会更简单(因此不需要Weak包装器),并且当可重写解引用可用时(无需额外的borrow()borrow_mut()调用)也会更简单。 - Vladimir Matveev
好的,谢谢回答。我现在正在考虑使用原始指针来引用容器,因为我知道它将至少存在于元素存在的时间内(程序中只有一个,并且它的生命周期与 main 相同)。不过我会关注 Gc 的发展情况。 - Kolja
1个回答

1
长串的方法调用对我来说实际上没有任何更改就在主分支上工作了,因为“r-values”的生命周期(例如函数调用的结果)已经发生了变化,使得临时返回值持续到语句结束,而不是下一个方法调用结束(这似乎是旧规则的工作方式)。正如弗拉基米尔所暗示的那样,可重载的解引用可能会将其减少到。
self.container.upgrade().unwrap().borrow_mut().poke();

无论如何,“变异”共享所有权在Rust中的编写都会比单一所有权代码或不可变共享所有权代码更加困难(略微困难),因为这种代码很容易导致内存不安全(而内存安全是 Rust 的核心目标)。

更好的选择取决于您的具体需求。如果您可以使用单个所有者模型,那么这通常是最简单和最安全的选择。但是,如果您需要多个所有者,那么您需要在安全性和灵活性之间进行权衡,并决定哪个方案最适合您的用例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接