gpt4 book ai didi

rust - 我应该如何重组图形代码以避免出现 "Cannot borrow variable as mutable more than once at a time"错误?

转载 作者:行者123 更新时间:2023-11-29 08:04:02 25 4
gpt4 key购买 nike

我有一个成功编译的简单图表:

use std::collections::HashMap;

type Key = usize;
type Weight = usize;

#[derive(Debug)]
pub struct Node<T> {
key: Key,
value: T,
}
impl<T> Node<T> {
fn new(key: Key, value: T) -> Self {
Node {
key: key,
value: value,
}
}
}

#[derive(Debug)]
pub struct Graph<T> {
map: HashMap<Key, HashMap<Key, Weight>>,
list: HashMap<Key, Node<T>>,
next_key: Key,
}
impl<T> Graph<T> {
pub fn new() -> Self {
Graph {
map: HashMap::new(),
list: HashMap::new(),
next_key: 0,
}
}
pub fn add_node(&mut self, value: T) -> &Node<T> {
let node = self.create_node(value);
node
}

fn create_node(&mut self, value: T) -> &Node<T> {
let key = self.get_next_key();
let node = Node::new(key, value);
self.list.insert(key, node);
self.map.insert(key, HashMap::new());
self.list.get(&key).unwrap()
}

fn get_next_key(&mut self) -> Key {
let key = self.next_key;
self.next_key += 1;
key
}
}

但是当我使用它时编译失败:

fn main() {
let mut graph = Graph::<i32>::new();
let n1 = graph.add_node(111);
let n2 = graph.add_node(222);
}

错误:

error[E0499]: cannot borrow `graph` as mutable more than once at a time
--> src/main.rs:57:14
|
56 | let n1 = graph.add_node(111);
| ----- first mutable borrow occurs here
57 | let n2 = graph.add_node(222);
| ^^^^^ second mutable borrow occurs here
58 | }
| - first borrow ends here

类似的问题我都看过了。我知道这是失败的,因为方法 Graph::add_node() 使用 &mut self。在所有类似的问题中,一般的答案是“重构你的代码”。我不明白我该怎么办?我应该如何重构这段代码?

最佳答案

通过返回 &Node<T>来自 add_node ,你有效地锁定了整个Graph<T>对象,因为你是从它那里借来的。并且有充分的理由;尝试运行这个 main :

fn main() {
let mut graph = Graph::<i32>::new();
let n1 = graph.add_node(111) as *const _;
let mut inserts = 0;
loop {
inserts += 1;
graph.add_node(222);
let n1bis = graph.list.get(&0).unwrap() as *const _;
if n1 != n1bis {
println!("{:p} {:p} ({} inserts)", n1, n1bis, inserts);
break;
}
}
}

这是该程序的可能输出:

0x7f86c6c302e0 0x7f86c6c3a6e0 (29 inserts)

此程序添加第一个节点并将其地址存储为原始指针(原始指针没有生命周期参数,因此释放了对 Graph 的借用)。然后,它添加更多节点,一次一个,然后再次获取第一个节点的地址。如果第一个节点的地址发生变化,它会打印这两个地址以及插入到图中的其他节点的数量。

HashMap使用随机散列,因此每次执行时插入的数量会有所不同。但是,它最终需要重新分配内存以存储更多条目,因此最终, map 中节点的地址会发生变化。如果您在发生这种情况后尝试取消引用旧指针(例如 n1),那么您将访问释放的内存,这可能会返回垃圾数据或导致错误(通常是段错误)。

了解了这一切,应该清楚add_node不应返回 &Node<T> .以下是一些备选方案:

  • 制作add_node什么都不返回,或者返回 Key , 并提供一个单独的方法来获取 &Node<T>给了一把 key 。
  • 将您的节点包装在 Rc<T> 中或 Arc<T> .也就是说,而不是 list作为HashMap<Key, Node<T>> , 这将是一个 HashMap<Key, Rc<Node<T>>> .你可以clone()一个RcArc复制指针并增加引用计数;在 HashMap 中存储一份副本并从 add_node 返回另一个副本.
    • 如果您还需要在保留改变图的能力的同时改变节点,您可能需要结合 Rc RefCell , 或 Arc Mutex .

关于rust - 我应该如何重组图形代码以避免出现 "Cannot borrow variable as mutable more than once at a time"错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36565833/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com