Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing an immutable reference when a mutable reference exists

I have a for loop that iterates over a slice of Point structs. The Points will have some fields modified in the loop, so the function containing the loop requires a mutable reference to the slice.

The problem arises when I need to pass a (immutable) reference pointing to the slice to a function within the for loop that iterates over the mutable reference:

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let mut grid = vec![];

    grid.push(Point { x: 10, y: 10 });
    grid.push(Point { x: -1, y: 7 });

    calculate_neighbors(&mut grid);
}

fn calculate_neighbors(grid: &mut [Point]) {
    for pt in grid.iter_mut() {
        pt.x = nonsense_calc(grid);
    }
}

#[allow(unused_variables)]
fn nonsense_calc(grid: &[Point]) -> i32 {
    unimplemented!();
}

Playground

error[E0502]: cannot borrow `*grid` as immutable because it is also borrowed as mutable
  --> src/main.rs:18:30
   |
17 |     for pt in grid.iter_mut() {
   |               ---------------
   |               |
   |               mutable borrow occurs here
   |               mutable borrow used here, in later iteration of loop
18 |         pt.x = nonsense_calc(grid);
   |                              ^^^^ immutable borrow occurs here

The compiler complains that grid cannot be borrowed as immutable, because a mutable borrow already exists. This is correct, and I can see the problem it is trying to prevent, but how do I achieve what I need to do? Ideally, I do not have to create a copy of the grid, as this can be expensive.

like image 340
tverghis Avatar asked Dec 20 '18 15:12

tverghis


1 Answers

A solution to avoid borrow the array for the iteration would be to use indexes:

fn calculate_neighbors(grid: &mut [Point]) {
    for i in 0..grid.len() {
        grid[i].x = nonsense_calc(grid);
    }
}
like image 128
Denys Séguret Avatar answered Oct 13 '22 23:10

Denys Séguret