The reason that you cannot have two
&mut references to the same value is that the language designers chose to enforce this rule. Now, you might ask, why did we choose this rule? Fundamentally it allows the compiler to ensure you never have a dangling reference, and any library author know they can depend on this.
Let’s take a look at the code below:
let list = vec![0, 1, 2, 3];
let a = &mut list;
*a = 10;
This code might resize the list, which would invalidate the
a reference. Now, why does this fail? Well the expression
&mut list borrows
list mutably, meaning that as long as
a exists, you cannot have another mutable reference to
&mut self method, it also requires a mutable reference to call it, so the borrow-checker will fail the code.
The creators of the
Vec library know that the compiler acts this way when it sees a mutable reference, so they can depend on it when they write their library. It would be much harder to write this kind of code if the compiler just says “well I prevent this kind of stuff sometimes, maybe, if I want to”, since then you can’t always depend on the compiler rejecting invalid code without understanding very well when it rejects the code.
Sync, it is possible to send a
&mut i32 to a different thread. If the compiler also allowed you to keep a reference to it in this thread, you could suddenly have the other threads writing to your variable while you read it. This is called a data race, and is undefined behaviour, so we do not allow it.
Now, of course, if we promise not to send it to a different thread, writing to it from several places is perfectly well defined. No two threads would be writing to it at the same time, which is what caused the problem. However the way you promise the compiler not to modify it from several threads at once, is to use a type that does not implement
Sync. Luckily the standard library includes the Cell type, which does not implement
Sync, and it allows you to set the value using the
set method. The reason this is safe is that since we don’t have
Sync, it can only ever be accessed from one thread at once.
Cell is also subject to the “only one
&mut reference” rule. All types are. This is why the
set method is a
&self method, not a
&mut self method. You can call a
&self method using only a immutable reference, and you can have several of those. Internally it works using what is called interior mutability.