我有一个成功编译的简单图表:
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
。在所有类似的问题中,一般的答案是&#34;重构您的代码&#34;。我无法理解我该怎么办?我该如何重组此代码?
答案 0 :(得分:4)
从&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
使用随机散列,因此每次执行时插入的数量会有所不同。但是,它将最终需要重新分配内存以存储更多条目,因此最终,地图中节点的地址会发生变化。如果您在发生这种情况后尝试取消引用旧指针(例如n1
),那么您将访问释放的内存,这可能会返回垃圾数据或导致错误(通常是分段错误)。
了解这一切后,应该清楚add_node
不应该返回&Node<T>
。以下是一些替代方案:
答案 1 :(得分:1)
我使用 int[] input = {4,7,2,6,3,5,1,0}
int cmpt = 0 ;
int totalFalses ;
final int[] posi =new int[31];
Arrays.parallelSetAll(posi, i -> i );
OptionalInt max = Arrays.stream(input).parallel().max();
int d_max = RadixSort.log2nlz(max.getAsInt());
for( int p : posi) {
System.out.println("=========new loop ==========");
int[] b = Arrays.stream(input).parallel().map(x -> x >> p & 1 ).toArray();
//take into account the bit.
System.out.println("b= " + Arrays.toString(b) );
//reverse the bit and make a exclusive prefix sum !
int[] e_f = Arrays.stream(input).parallel().map(x -> ~x >> p & 1 ).toArray();
totalFalses = e_f[e_f.length-1] ;
//Doing the prefix sum exclusive with a function created. The one from java is inclusive.
ParallelPrefixSum PPS = new ParallelPrefixSum(e_f , 0, e_f.length-1,RadixSort.log2nlz(e_f.length-1)) ;
try {
PPS.scan();
} catch (Exception e) {
e.printStackTrace();
}
totalFalses += e_f[e_f.length-1] ;
System.out.println("e_f= " + Arrays.toString(e_f) );
int totalFalsetmp = totalFalses;
//create and compute t arrays
int[] t = new int[input.length] ;
Arrays.parallelSetAll(t, i -> i - e_f[i] + totalFalsetmp ) ;
System.out.println("t= " + Arrays.toString(t) );
//create and compute d arrays
int[] d = new int[input.length] ;
Arrays.parallelSetAll(d, i -> (b[i]==1)?t[i]:e_f[i]) ;
System.out.println("d= " + Arrays.toString(d) );
//place element in the rigth order
int[] tmp = input ;
int[] output = new int[input.length];
IntStream.range(0, input.length).forEach(i -> output[d[i]] = tmp[i]);
input = output ;
if(cmpt >= d_max){
break ;
}
cmpt ++ ;
}
解决了问题:
std::rc::Rc