Here is the problem : I would like to iterate through the next_node attribute of a gateway, and add 1 to the attribute nb_link_to_gateway to all nodes listed.
I wrote this code :
for node in &nodes[ei].next_node{
nodes[*node].link_to_gateway += 1;
}
*note : nodes[ei] is pointing to a gateway.
Which gives me this error:
error[E0502]: cannot borrow `nodes` as mutable because it is also borrowed as immutable
--> /tmp/Answer.rs:64:17
|
63 | for node in &nodes[ei].next_node{
| --------------------
| ||
| |immutable borrow occurs here
| immutable borrow later used here
64 | nodes[*node].link_to_gateway += 1;
| ^^^^^ mutable borrow occurs here
I understand the error, but I don't know how to remove it. I tried different solution, all gives the same result.
So the fundamental problem here is that the compiler can't prove that node will never be equal to ei and thus you are not reading and writing the same value at the same time.
As the simplest solution, if this piece of code isn't yet a performance bottleneck, you could just clone the vector:
for node in nodes[ei].next_node.clone() {
nodes[node].link_to_gateway += 1;
}
If you want to avoid cloning at all costs, you could split the vector instead and juggle indices around:
let (before, tmp) = nodes.split_at_mut(ei);
let (gateways, after) = tmp.split_at_mut(1);
let gateway = &gateways[0];
for &node in &gateway.next_node {
if node < ei {
before[node].link_to_gateway += 1;
} else {
after[node - ei - 1].link_to_gateway += 1;
}
}
I'm not at all sure though that the latter performs better than the former, because it involves array bounds checking and a conditional on every iteration. My guess would be that when there are typically few elements in the next_node vectors, then the memory allocation overhead of cloning is slower than a couple conditionals, but if there are a lot of node indices in next_node, then the resulting array bounds checks and conditionals will dominate the time of a one-off cloning.
The code is not that critical and is only used once.
I suppose that if I want to change
next_node : Vec<usize>
to
next_node : Vec<&'static Node>
the same solutions will work. But I don't know if, in this situation, it's a better data structure. I tend to think not.
Also, isn't there a system to tell the compiler to dot less check on the code ? I think about the 'unsafe' feature. It could bypass the problem ? I tried using it, but i don't know if I used it correctly or if it does not bypass the checks associated to the error E0502.
I like that solution. It's almost as simple as cloning and doesn't involve lots of conditionals. However, I think it can be simplified a bit more, working with values rather than references (@thenewbby):
let next_node = mem::replace(&mut nodes[ei].next_node, Vec::new());
for &node in &next_node {
nodes[node].nb_link_to_gateway += 1;
}
mem::replace(&mut nodes[ei].next_node, next_node);