Usage of mutable reference having one immutable

Hello,
Every time i try to compile implementation of one of advent of code's task I get following error:

error[E0502]: cannot borrow `wires` as mutable because it is also borrowed as immutable
   --> src/main.rs:205:20
    |
195 |   let mut collision = Collision::new(&wires);
    |                                      ------ immutable borrow occurs here
...
205 |   for each_wire in &mut wires {
    |                    ^^^^^^^^^^ mutable borrow occurs here
206 |     each_wire.get_shortest_num_of_moves_for_collision(&collision_pts);
    | 

Here is my code:

  let mut collision = Collision::new(&wires);
  let collision_pts: Vec<&Point> = collision.detect_on_wires();
  println!("Found collision points: {:?}", collision_pts);

  // part 1
  let shortest_dist = get_shortest_distance(&collision_pts);
  println!("Shortest distance: {}", shortest_dist);

  // part 2
  let shortest_moves_for_collisions: Vec<u32> = vec![];
  for each_wire in &mut wires {
    each_wire.get_shortest_num_of_moves_for_collision(&collision_pts);
  }

And fragment of Collision structure:

struct Collision <'a> { wires: &'a [Wire] }
impl <'a> Collision <'a> {
  pub fn new(wires: &[Wire]) -> Collision {
    Collision {
      wires: wires
    }
  }

The problem is that Collision::new(.. uses immutable reference to wires, but then I need to perform some operations on wire elements. I know that this is a problem and I can't have mutable and immutable references of same element at the same time, but to be hones I have no idea how to solve that. Could you please explain me how to avoid such situations? Regards!

Does Collision only have that one field wires (or did you cut out the rest for simplicity's sake)?

Yes, it only has wires field

Is Wire your own type or is it contained in an external module?

Also, does Point contain a reference to Wire?

Both structures are mine. Here you have some more code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eb96026c9154b18a7cc40a5741c1975e

Depending on how Point is defined, it might even be cheaper to copy it than to reference it.

Please post the type definitions in this thread.

Get rid of the Collision struct. Convert the methods of Collision into free-standing functions, that take &[Wire] as their first argument. You never mutate Collision and it doesn't own anything, i.e. chances are very high the struct is useless.

You can define a type alias, instead, if you want to:

type Collision<'a> = &'a [Wire];

fn detect_collision_pts(collision: Collision<'_>) { … }

Yeah, that is a solution and it will definitely work in this case, but I can think of some cases in which having such struct will be required and my question remains valid. Do you have idea of handling those? I mean, is there any chance in which my implementation may work?
Regards!

What happens, if you get rid of the collision variable and instead just use collision like this?

let collision_pts: Vec<&Point> = Collision::new(&wires).detect_on_wires();

You may have to wrap Collision::new() in pair of (). Not sure if Rust likes Type::method().method().

Then we have a new error:
219 | let collision_pts: Vec<&Point> = Collision::new(&wires).detect_on_wires();
| ^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
:smiley:

After some analysis it wont solve it either :frowning: Problem is that i still need to borrow 'wires' twice.

  1. First time in
    let collision_pts: Vec<&Point> = detect_on_wires(&wires);
  2. Second time in
    for each_wire in &mut wires {
    each_wire.get_shortest_num_of_moves_for_collision(&collision_pts);
    }

Result is the same -> I have mutable and immutable reference for the same variable :frowning:

Return Vec<Point> instead of Vec<&Point>. Derive Copy and Clone for Point.

3 Likes

Thank you all for your help :slight_smile: