What's the difference of `mut` in type declaration and variable declaration?

This example will complain cannot borrow immutable local variable array as mutable
However if adding another mut in reverse function signature before array, namely changing
fn reverse(array: &mut[i32], lo: usize, hi: usize)
to
fn reverse(mut array: &mut[i32], lo: usize, hi: usize)
then everything is ok.

So what is the difference between the two mut (before array and after array)?

array: &mut[i32] is a mutable borrowed pointer - that is, you can mutate the array value that it's pointing to. On the other hand you can't mutate the pointer itself. The following code, for instance, doesn't compile, because the last line tries to assign a new value to a:

    let mut b = 4;
    let a: &mut i32 = &mut 3;
    a = &mut b;

But if you change the second line to let mut a: &mut i32 = &mut 3; then everything's fine.

It looks like the probjem in your code is actually not the function declaration, it's the line reverse(&mut array, lo+1, hi-1);. array has type &mut [i32]. When you do &mut array the result is a mutable pointer to the pointer array, which has type &mut &mut [i32]. Because array is immutable the compiler can't create a mutable reference to it. Change that line to reverse(array, lo+1, hi-1); and everything's fine.

I'm really surprised that you can pass an &mut &mut T to a function taking an &mut T, though.

&mut T implements DerefMut, so the compiler can coerce from &mut &mut T to &mut T, which are the input and output types of <&mut T as DerefMut>::deref_mut respectively.

2 Likes

FYI This is called deref-coercion.