 # Vector of struct : iterate through struct attribute to modify other struct in same vector ==> E0502

Hey Rustaceans !

I have a small problem with vectors at the moment, nothing extraordinary but i'm struggling to code what I want.

I have a vector of a a custom struct :Node.

``````struct Node{
is_gateway : bool,
next_node :  Vec<usize>,
}
``````

As you can see nothing too fancy.

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{
}
``````

*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
|
63 |             for node in &nodes[ei].next_node{
|                         --------------------
|                         ||
|                         |immutable borrow occurs here
|                         immutable borrow later used here
|                 ^^^^^ 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.

Any ideas how to do it ?

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() {
}
``````

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;

for &node in &gateway.next_node {
if node < ei {
} 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.

1 Like

You could take `next_node` out the time of the iteration and put it back afterwards.

``````let mut next_node = Vec::new();
std::mem::swap(&mut next_node, &mut nodes[ei].next_node);

for &node in &next_node {
}

std::mem::swap(&mut next_node, &mut nodes[ei].next_node);
``````
2 Likes

I see, thank's for your solutions. ^^

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.

If it's not performance-critical, don't even think about `unsafe`.

All right . I will stay in the safe zone.

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 {