【问题标题】:cannot borrow as mutable because it is already borrowed, when implementing graph在实现图时,不能像可变一样借用,因为它已经被借用了
【发布时间】:2021-09-17 13:35:44
【问题描述】:

我试图通过让每个节点存储对其邻居的引用来实现图形结构。具体来说,我正在尝试创建一个网格,其中每个节点最多可以引用 4 个邻居 - 就像一个“二维链表”。

但我在分配引用时遇到错误。这个简约的例子重现了我的问题:

#[derive(Clone)]
struct Node<'a> {
    neighbor: Option<&'a Node<'a>>, // optional reference to another Node
}

fn main() {

    // a bunch of nodes:
    let mut nodes: Vec<Node> = vec![ Node{neighbor: None}; 100];

    // I want node 0 to have a reference to node 1
    nodes[0].neighbor = Some(&nodes[1]);

}

产生以下错误:

error[E0502]: cannot borrow `nodes` as mutable because it is also borrowed as immutable
  --> src/main.rs:12:5
   |
12 |     nodes[0].neighbor = Some(&nodes[1]);
   |     ^^^^^------------------------------
   |     |                         |
   |     |                         immutable borrow occurs here
   |     mutable borrow occurs here
   |     immutable borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.

我正在努力弄清楚这应该如何在 Rust 中完成。我应该改用指针吗?

【问题讨论】:

  • 为什么不存储索引而不是节点本身的引用?
  • 我希望能够使程序的其余部分独立于用于实例化节点的结构。但也许这在 Rust 中是个坏主意?
  • 你绝对可以这样做,只是索引也很简单。你可能想看看Rc
  • GhostCell 可能会为您提供帮助,它正是为此目的而制作的。 Here's a github repo with some collections using ithere's a reddit post about a 1d linked list
  • ...如果没有任何安全方法适合您(人体工程学、性能等),您可以随时使用不安全的块和原始指针

标签: rust borrow-checker


【解决方案1】:

由于创建借用检查器的原因,您不能完全实现这种数据结构。它告诉你你的数据结构不安全。

它不安全的原因很简单。

假设您创建了一个包含两个元素的图表,第一个元素引用了第二个元素。现在您希望第二个引用第一个。要修改您的图表,您需要获得对结构的可变访问权限。但是,如果您获得对它的可变访问权限,则没有什么可以阻止您从图中删除第二个节点,从而使第一个节点中的引用无效。

因此,借用检查器不允许您这样做。

适合您的方法是使用索引而不是引用。这将具有额外的优势:当您想要序列化/反序列化您的结构时,您将完全没有问题。

【讨论】:

  • 可以通过Rc/Weak使用堆分配的节点来实现这一点
  • 谢谢,我现在明白为什么这是不允许的了,和我最初想的不同,这不是编译器的缺陷
  • ...但是,在可以删除节点的假设场景中,我不得不想知道索引实现有什么好处。从编译器的角度来看,它是“安全的”,当然,但索引会像引用一样变得无效。
  • 如果你欺骗编译器(例如使用不安全的)并让它让你使用引用,并且不小心取消引用无效引用,你就会有内存访问冲突。这是一个更糟糕的问题,更难以调试,然后在不检查的情况下使用不正确的索引时会恐慌。
猜你喜欢
  • 2018-05-17
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多