我应该如何重组图形代码以避免 "Cannot borrow variable as mutable more than once at a time" 错误?
How should I restructure my graph code to avoid an "Cannot borrow variable as mutable more than once at a time" error?
我有一个成功编译的简单图表:
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
。在所有类似的问题中,一般答案是"restructure your code"。我不明白我该怎么办?我应该如何重构这段代码?
通过 return 从 add_node
获取 &Node<T>
,您实际上锁定了整个 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
使用随机散列,因此每次执行时插入的数量会有所不同。但是,它将最终需要重新分配内存以存储更多条目,因此最终,地图中节点的地址会发生变化。如果您在发生这种情况后尝试取消引用旧指针(例如 n1
),那么您将访问释放的内存,这可能 return 垃圾数据或导致错误(通常是分段错误)。
了解了这一切,应该清楚add_node
不应该return一个&Node<T>
。这里有一些备选方案:
我使用 std::rc::Rc
:
解决了问题
use std::collections::HashMap;
use std::rc::Rc;
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, Rc<Node<T>>>, // <-- Changed
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) -> Rc<Node<T>> {
// <-- Changed
let key = self.get_next_key();
let node = Rc::new(Node::new(key, value)); // <-- Changed
self.list.insert(key, node.clone()); // <-- Changed
self.map.insert(key, HashMap::new());
node
}
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);
}
我有一个成功编译的简单图表:
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
。在所有类似的问题中,一般答案是"restructure your code"。我不明白我该怎么办?我应该如何重构这段代码?
通过 return 从 add_node
获取 &Node<T>
,您实际上锁定了整个 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
使用随机散列,因此每次执行时插入的数量会有所不同。但是,它将最终需要重新分配内存以存储更多条目,因此最终,地图中节点的地址会发生变化。如果您在发生这种情况后尝试取消引用旧指针(例如 n1
),那么您将访问释放的内存,这可能 return 垃圾数据或导致错误(通常是分段错误)。
了解了这一切,应该清楚add_node
不应该return一个&Node<T>
。这里有一些备选方案:
我使用 std::rc::Rc
:
use std::collections::HashMap;
use std::rc::Rc;
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, Rc<Node<T>>>, // <-- Changed
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) -> Rc<Node<T>> {
// <-- Changed
let key = self.get_next_key();
let node = Rc::new(Node::new(key, value)); // <-- Changed
self.list.insert(key, node.clone()); // <-- Changed
self.map.insert(key, HashMap::new());
node
}
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);
}