无法作为可变借用进行借用,因为它已经被借用,在实现图时遇到该问题。

4

我正在尝试通过让每个节点存储对其邻居的引用来实现图形结构。具体而言,我正在尝试创建一个网格,其中每个节点都有对高达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中应该如何完成这项任务。我应该使用指针吗?


2
为什么不存储索引而不是节点本身的引用? - Netwave
我希望我的程序的剩余部分能够独立于用于实例化节点的这个结构。但也许在Rust中这样做不是一个好主意? - Maze
1
你可以完全这样做,只是索引也很简单。你可能需要看一下 Rc - Netwave
1
可能GhostCell可以帮助您,它就是为此目的而制作的。这里有一个使用它的GitHub仓库,以及这里有一个Reddit帖子介绍1D链表 - Misty
1
如果没有安全方法适合你(例如人体工程学、性能等),你可以随时回退到不安全的块和原始指针。 - Misty
1个回答

4

由于借用检查器的存在,您无法完全实现此类数据结构。它告诉您的数据结构可能不安全。

原因很简单。

假设您创建了一个具有两个元素的图表,并且第一个元素引用第二个元素。现在您想让第二个元素引用第一个元素。要修改图表,您需要获取可变访问权限。但是如果您获得了对其的可变访问权限,则没有任何东西可以阻止您从图表中删除第二个节点,使第一个节点中的引用无效。

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

您应该使用索引而不是引用。这将有额外的好处:当您想要序列化/反序列化结构时,您将完全没有问题。


3
通过使用堆分配节点和Rc/Weak,可以实现这一点。 - Svetlin Zarev
谢谢,我现在明白为什么这是不允许的了。与我最初想的不同,这并不是编译器的缺陷。 - Maze
1
然而,在节点可以被删除的假设场景中,我不禁想知道索引实现有什么好处。从编译器的角度来看它是“安全”的,但索引就像引用一样会变得无效。 - Maze
1
如果你欺骗编译器(例如使用不安全的代码),让它允许你使用引用,并意外地对无效的引用进行解引用,那么你将会遇到内存访问冲突。这是一个更严重的问题,也比未经检查使用不正确的索引导致的崩溃更难以调试。 - Maxim Gritsenko

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