 # Mutable and immutable in loop

Hi, I'm sure this is noob stuff but...here it goes

``````    let mut numbers: Vec<u32> = (1..100).collect();
let mut last_index = 0;

while !numbers.is_empty() {
let next = numbers.iter().enumerate().filter(|(_, number)| last_index % **number == 0).next();
if let Some((index, removed)) = next {
numbers.remove(index);
println!("removed {} @ {}", removed, index);
}
last_index += 3;
}
``````

which, naturally, results in the error

``````cannot borrow `numbers` as mutable because it is also borrowed as immutable

mutable borrow occurs hererustc(E0502)
main.rs(83, 20): immutable borrow occurs here
main.rs(85, 13): mutable borrow occurs here
main.rs(86, 41): immutable borrow later used here
``````

How would one go about solving these kinds of issues, i.e., an item is selected from the vector based on some logic that iterates it and then it is removed?

Thank you for you patience.

`Vec::retain()` is useful for a lot of situations like this, but it doesn't provide access to the index of the item. I'm having trouble understanding what this code is actually trying to do, so it's hard to propose an alternative.

Edit: In this particular case, you don't need to get a reference to the item from the iterator because `Vec::remove` will return it:

``````fn main() {
let mut numbers: Vec<u32> = (1..100).collect();
let mut last_index = 0;

while !numbers.is_empty() {
let next = numbers.iter()
.enumerate()
.find(|&(_, &number)| last_index % number == 0)
.map(|(i,_)| i);
if let Some(index) = next {
let removed = numbers.remove(index);
println!("removed {} @ {}", removed, index);
}
last_index += 3;
}
}
``````
1 Like

The `let next` line can be simplified using `.position`:

``````let next = numbers.iter().position(|&number| last_index % number == 0);
``````
3 Likes

The code provided is a simplified version of what I need and the smallest I could get that would cause the issue. Your solution doesn't cause the issue and I don't understand why and, thus, (still) help. Could you, please, explain the rational that makes your code work even when both mutable and immutable borrows live inside a loop?

Your original code, with some type annotations:

``````        let next: Option<(usize, &u32)> = numbers.iter()
.enumerate()
.filter(|(_, number)| last_index % **number == 0)
.next();
``````

Note that `next` includes a reference to the `u32` which is still in your `Vec`. This is what is causing the conflict: You try to `remove` something from your `Vec` while still holding on to a reference that points into that same `Vec`. You then try to use that reference, in the `println!` after the `remove`.

If your code is in fact dealing with `u32` or any other `Copy` type, this would be enough to fix it:

``````        // Type is now `Option<(usize, u32)>`
let next = numbers.iter()
.enumerate()
.filter(|(_, number)| last_index % **number == 0)
.map(|(i, n)| (i, *n)) // <-- new
.next();
``````

Here, we make a copy of the value instead of taking a reference to the value. It's one way of getting rid of the reference to satisfy the borrow checker.

Hopefully this explains the problem for you. It's not that there are both mutable and immutable borrows in the loop at all, but rather that there are mutable and immutable borrows active at the same time. In fact, another way to make your example compile is to remove the `println!`, because then the reference can be discarded before the `remove` -- you don't use it anymore. (I've assumed you need the `println!` or at least the value, though.)

However @2e71828's solution is more general (i.e. better) in that it finds the index, discards the reference entirely, and then uses the result of `remove` to capture the removed value. It doesn't require that the values in the `Vec` be `Copy`. But it avoids the error for similar reasons -- it gets rid of the reference that was causing a conflict.

(They also ergonomically replaced `filter() + next()` with `find()`.)

1 Like

And here's a couple programs that produce the same output with no `Vec`. I believe they will be the same for any value of `limit`, but haven't proved it rigorously . See also.

1 Like

Thank you for the eloquent clarity. I stand elucidated.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.