Search code examples
rustslicemutabilityborrowing

Why can't I print an array after I've taken a slice of it in Rust?


Why can't I pass data to a function when that function is not going to modify it and the ownership context doesn't end there?

This code gives an error:

let mut ar = [1, 2, 3, 4, 5];
let slice = &mut ar[1..=3];
slice[1] = 9;
println!("{:?} ", slice);
for e in ar.iter(){
    println!("{}", e)
}

This is the error:

error[E0502]: cannot borrow `ar` as immutable because it is also borrowed as mutable
 --> src/main.rs:6:14
  |
3 |     let slice = &mut ar[1..=3];
  |                      -- mutable borrow occurs here
...
6 |     for e in ar.iter() {
  |              ^^ immutable borrow occurs here
...
9 | }
  | - mutable borrow ends here

My guess is that we can't pass the array to the println! function because we have borrowed it, but I can't understand why. It's not like the println! function will change it!

I find the following behaviour difficult to understand. How can I print an array if I have slices of it?

This code works and prints [2, 9, 4]

let mut ar = [1, 2, 3, 4, 5];
let slice = &mut ar[1..=3];
slice[1] = 9;
println!("{:?} ", slice);

Also, this code works and prints everything properly, by modifying the slice we modify the original array!

let mut ar = [1, 2, 3, 4, 5];
{
    let slice = &mut ar[1..=3];
    slice[1] = 9;
    println!("{:?} ", slice); // -> [2, 9, 4]
}
for e in ar.iter(){
    println!("{}", e) //-> 1 2 9 4 5 as expected since the slice has changed
}

Solution

  • It seems you've already found the answer if your last example, but you still seem a little confused.

    The println! here isn't the problem at all (note how the error message, which is actually very accurate here, doesn't mention it at all). The problem is that the slices variable is mutably borrowing from ar, and slices still exists when ar.iter() tries to borrow from ar. You can't have a mutable and immutable borrow at the same time, so the compiler stops you.

    One solution, as you already found, is to ensure that the mutable slices borrow doesn't exist when you use ar.iter() (which borrows ar).


    As for why the compiler is stopping you from doing this, it's because it doesn't want the value of an immutable borrow to unexpectedly change from under you. Basically, when you immutably borrow ar for ar.iter, it would be very strange if the underlying data suddenly changed. But since slice is already mutably borrowing the same data you could put some code in your loop that changes ar via slice, which would affect the iterator. The compiler doesn't want you doing this. The way it guarantees that you can't is by ensuring that no mutable borrow (slice in this case) exists when you make the immutable borrow. Right now, it doesn't check whether there is code that is actually trying to use the mutable borrow in the loop, it just guarantees that there couldn't possibly be.