From rust book:
At any given time, you can have either one mutable reference or any number of immutable references.
Consider the following code:
fn main() {
let mut a = 41;
let b = &mut a;
let c: &i32 = &a; // [1]
let d: &i32 = &b;
println!("{} {}", b, c); // [2]
println!("{} {}", b, d);
}
If we try to compile we get:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src\main.rs:43:19
|
42 | let b = &mut a;
| ------ mutable borrow occurs here
43 | let c: &i32 = &a; // [1]
| ^^ immutable borrow occurs here
44 | let d: &i32 = &b;
| -- mutable borrow later used here
... so, the rule about having only one mutable reference checks out.
However, if you comment lines marked [1] and [2], everything compiles fine. Note that in this case b is mutable reference amd d is immutable reference (seems to be the same as c).
Why are we allowed this situation and why this case compiles without violating rule about having either one mutable reference or n immutable references?
Here, the book has simplified things in order to more quickly convey information. In reality, you can actually have as many mutable references as you want.
The actual restriction is that only one mutable reference can be active at any point. This also applies to the original owner.
So when
cis created above, you enter a region where you can passcto functions likef, usecto create other borrows liked, or change ownership ofclikee. You aren't allowed to do any of those withbuntil after the last timecis used. And when you created, you enter another region whereccan't be used. Sincedis never used, this region ends immediately andconce again becomes active.This should make sense since without it, mutable references would be extremely limited. For example, every function that takes a mutable reference like
fn f(x: &mut i32)makes a new temporary borrow from what you pass into it. If it didn't, you would only be able to use the mutable borrow one time.This explains why your original code doesn't work. You're trying to use
awhilebis active.Here's your second version:
I'm going to make two changes that don't change any of the borrowing relationships. First,
let d: &i32 = &b;gets automatically expanded by the compiler tolet d: &i32 = &*b;. If it didn't, this would try to assign a&&mut i32to a variable of type&i32and would not compile. Second, theprintln!macro adds a reference to each of its arguments for convenience. This is something only a macro can do invisibly; when functions take references, it is always explicit. I'm replacingprintln!with a function so that you can see how each variable is actually borrowed.From what I wrote above, this would seem to not work, since you're using
band then usingdright after. But there is one other thing that mutable references (as well as the owner and immutable references) are allowed to do: produce any amount of immutable references. As soon as one immutable reference is given out, you enter a region where you can use the immutable reference and create more immutable references. In this case,bcreates one immutable reference to its contents (essentially&a, with type&i32) and one immutable reference to itself (with type&&mut i32).So with that in mind, the code above goes like this:
ais created as the owneracreates mutable referenceband becomes completely inactivebcreates immutable referencedand becomes partially inactivebitself (still partially inactive)ditselfprintJust before
mainends, the two references given toprintand the referencedexpire, makingbactive again.bthen expires, makingaactive again. Thenais dropped, andmainends.