Why I can't borrow immutable reference of a mutable reference - rust

let mut v = vec![1, 2, 3];
let r = &mut v;
let rr = &r;
r.push(4);
println!("{:?}, {:?}", r, rr);
Gives error:
error[E0502]: cannot borrow `*r` as mutable because it is also borrowed as immutable
|
86 | let rr = &r;
| -- immutable borrow occurs here
87 | r.push(4);
| ^^^^^^^^^ mutable borrow occurs here
88 | println!("{:?}, {:?}", r, rr);
| -- immutable borrow later used here
I understand the concept of immutable reference can not be borrowed for *r, if there is already a borrowed mutable reference of *r. However, in this case I am trying to borrow immutable reference of r, not of *r.

A reference is just a variable, like any other variable.
If you replace the variable r with an integer, you should see why this isn't possible:
fn main() {
let mut r = 10;
let rr = &r;
r += 2;
println!("{:?}, {:?}", r, rr);
}
error[E0506]: cannot assign to `r` because it is borrowed
--> src/main.rs:4:5
|
3 | let rr = &r;
| -- borrow of `r` occurs here
4 | r += 2;
| ^^^^^^ assignment to borrowed `r` occurs here
5 | println!("{:?}, {:?}", r, rr);
| -- borrow later used here
Any mutable variable automatically becomes immutable while an immutable reference to it exists.
If that weren't the case, the owner of the rr variable couldn't rely on the fact that the content of rr never changes while he has the reference, which is one of the main points of immutable references. It doesn't just mean that you can't modify the variable, but you can also rely on the fact that no one else modifies it while you hold the reference.
So the pure existence of rr makes r temporarily immutable. r will automatically become mutable again once rr stops existing, but as you println!(/*..*/, rr) later, you force rr to stay alive until then and you force r to be immutable. That's why the modification fails.
The fact that in your code r is a reference doesn't change anything about this language mechanism. In your code, if this wouldn't error, the value rr references would change while rr exists. And again, the fact that rr is an immutable reference guarantees that the content that rr is referencing won't change.
Remark: The way I worded 'mutability' in this answer is somewhat incomplete, as 'interior mutability' exists, but it was easier to describe it this way. In reality, the words 'mutability' and 'immutability' should be replaced with 'exclusive access' and 'non-exclusive access'.

Related

When should I make a closure mut?

Let's say I have this code:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
c();
It doesn't compile and generates this error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src\test.rs:120:9
|
119 | let c = || s.push_str(" yo");
| - - calling `c` requires mutable binding due to mutable borrow of `s`
| |
| help: consider changing this to be mutable: `mut c`
120 | c();
| ^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `test` due to previous error
Why c(); cannot borrow as mutable? It cannot borrow what as mutable? c? In order to make it work, I have to change it to:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
c();
But here I'm just defining a closure c. I'll not modify it, like c = || x;. Why must define it as let mut c?
But here I'm just defining a closure c. I'll not modify it, like c = || x;. Why must define it as let mut c?
Because a closure is fundamentally a structure, each captured item being a member of that structure.
So your code is roughly equivalent to this:
struct S<'a>(&'a mut String);
impl S<'_> {
fn call(&mut self) {
self.0.push_str("yo");
}
}
fn main() {
let mut s = "hi".to_string();
let c = S(&mut s);
c.call();
}
And that fails to compile with more or less the same error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src/main.rs:14:5
|
13 | let c = S(&mut s);
| - help: consider changing this to be mutable: `mut c`
14 | c.call();
| ^^^^^^^^ cannot borrow as mutable
Now you might object that that's because I defined fn call(&mut self), but if you don't you get the internal part of the same error:
error[E0596]: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
--> src/main.rs:8:9
|
7 | fn call(&self) {
| ----- help: consider changing this to be a mutable reference: `&mut self`
8 | self.0.push_str("yo");
| ^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
That is you can't modify an &mut through an &. Because if you did you could create multiple &s to the same &mut through which you could modify the pointee, and that would essentially give you multiple &mut.
Which is not allowed by Rust's semantics:
At any given time, you can have either one mutable reference or any number of immutable references.
It may not look like c needs to be mutable because you aren't modifying c itself, but for closure types, the mut keyword is what allows it to mutate any external state. It changes the type of the closure to be a FnMut, which the docs refer to as "a mutably capturing closure".
It's about ownership. mut here does not mean that you will mutate c, but that you require mut-level access to the closure in order to execute it.
c borrows s mutably. This should be fairly obvious, because calling c() modifies s.
Now imagine if c would be usable without mut:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
let c1 = &c;
let c2 = &c;
c1();
c2();
Here, both c1 and c2 would have mutable access to s simultaneously, which is not possible according to Rusts borrowing rules. This is prevented automatically by the compiler, as it changes the type of the closure to FnMut as soon as you access a variable mutably from within the closure.
Then, you need mut access to the closure to execute it and the case becomes a compiler error:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
let c1 = &mut c;
let c2 = &mut c;
c1();
c2();
error[E0499]: cannot borrow `c` as mutable more than once at a time
--> src/main.rs:5:10
|
4 | let c1 = &mut c;
| ------ first mutable borrow occurs here
5 | let c2 = &mut c;
| ^^^^^^ second mutable borrow occurs here
6 |
7 | c1();
| -- first borrow later used here

How borrow as mutable vs immutable in Rust?

I've read these docs: https://doc.rust-lang.org/rust-by-example/scope/borrow/mut.html
I've also read this question: (Cannot borrow immutable borrowed content as mutable)
The docs helped me understand how to declare borrowing as mutable (I think):
let mut (part1, part2) = someTuple;
But I'm haven't been able to find explicit instructions on what borrowing as an immutable looks like. This is my guess:
let (part1, part2) = someTuple;
I know this is a super basic question, but Googling it took me way off into the deep end of explanations and I'm still trying to get my bearings in the most simple of contexts.
How do I borrow as mutable vs an immutable in Rust?
let x = 0;
let immutable_borrow = &x; //borrow as immutable
//to borrow as mutable the variable needs to be declared as mutable
let mut y = 1;
let mutable_borrow = &mut y; //borrow as mutable
Note 1: you can borrow a variable either as immutable or mutable in the same scope, meaning you can't do this:
let mut x = 0;
let immutable_borrow = &x;
let mutable_borrow = &mut x;
Why?
Because if you would have mutable and immutable references of the same variable, then the data of that variable could change through that mutable reference and that could cause a lot of problems.
Note 2: you can immutably borrow a variable endless times but you can mutably borrow a variable only once.
//You can do this
let x = 0;
let x1 = &x;
let x2 = &x;
//...
//But you can't do this
let mut y = 0;
let y1 = &mut y;
let y2 = &mut y; //won't compile if you use y1 after you declare y2
Why?
As mentioned above. One mutable reference could change the data all the other mutable references are poiting to without them knowing. That could cause a lot of problems. But having multiple immutable references is okay, because the data can't be unexpectedly changed.
Ejdrien answers demonstrates the difference between mutable and immutable borrows, however it does not address a subtitle in your question, which is that you are performing borrows as part of pattern matching.
When you write
let (mut part1, mut part2) = someTuple;
you are binding the contents of someTuple to the mutable variables part1 and part2 by moving them. Unless the contents of someTuple were Copyable, the variables part1 and part2 become the exclusive owners of their respective values. If you attempt to access someTuple later by writing, e.g.
println!("{}", someTuple.0);
you'll receive a compile error from the borrow checker that resembles
error[E0382]: borrow of moved value: `someTuple.0`
--> main.rs:6:20
|
4 | let (mut part1, mut part2) = someTuple;
| --------- value moved here
5 |
6 | println!("{}", someTuple.0);
| ^^^^^^^^^^^ value borrowed here after move
In this particular context, there are two ways to inform the compiler that we want to only borrow the contents of someTuple. The first is the technique that Ejdrien described, which is explicitly borrowing the tuple and the performing the pattern matching against then resulting reference:
// Produce two mutable references
let (part1, part2) = &mut someTuple;
// Produce two immutable references
let (part1, part2) = &someTuple;
The problem with this approach is that we are forced to borrow everything in the same way. What if we only want a mutable reference to someTuple.0, and want to retrieve someTuple.1 as a copy, or as an immutable reference? For the tuple example here, this may not seem too critical, but for more complex cases of pattern matching, having this type of control is much more important.
This brings us two the second solution: binding references. Instead of the above, we can write
// Produce two mutable references
let (ref mut part1, ref mut part2) = someTuple;
// Produce two immutable references
let (ref part1, ref part2) = someTuple;
Here, we explicitly state how we want to bind each variable in the pattern matching. The key here is that we are free to intermix mutable and immutable borrows, so the following is also entirely valid:
// Produce immutable reference and one mutable reference
let (ref part1, ref mut part2) = someTuple;
println!("{}", &someTuple.0); // Make a second immutable reference someTuple.0
*part2 = ... // Mutate someTuple.1
println!("{}", part1); // Continue using the immutable reference
If we swap the above with an explicit mutable borrow on the right hand side, we'll once again receive errors from the borrow checker due to simultaneous mutable and immutable references:
let (part1, part2) = &mut someTuple;
println!("{}", &someTuple.0);
*part2 = ... // Mutate someTuple.1
println!("{}", part1);
produces
error[E0502]: cannot borrow `someTuple.0` as immutable because it is also borrowed as mutable
--> main.rs:6:20
|
4 | let (part1,part2) =&mut someTuple;
| -------------- mutable borrow occurs here
5 |
6 | println!("{}", &someTuple.0);
| ^^^^^^^^^^^^ immutable borrow occurs here
...
9 | println!("{}", part1);
| ----- mutable borrow later used here
error: aborting due to previous error

Changing a vector in place using its values as indices without violating Rust's borrowing rules [duplicate]

What does the error mean in this case:
fn main() {
let mut v: Vec<usize> = vec![1, 2, 3, 4, 5];
v[v[1]] = 999;
}
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:3:7
|
3 | v[v[1]] = 999;
| --^----
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
I found that indexing is implemented via the Index and IndexMut traits and that v[1] is syntactic sugar for *v.index(1). Equipped with this knowledge, I tried to run the following code:
use std::ops::{Index, IndexMut};
fn main() {
let mut v: Vec<usize> = vec![1, 2, 3, 4, 5];
*v.index_mut(*v.index(1)) = 999;
}
To my surprise, this works flawlessly! Why doesn't the first snippet work, but the second one does? The way I understand the documentation, they should be equivalent, but this obviously isn't the case.
The desugared version is slightly different than what you have. The line
v[v[1]] = 999;
actually desugars to
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
This results in the same error message, but the annotations give a hint as to what's happening:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:7:48
|
7 | *IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
| ------------------- ------ ^^ immutable borrow occurs here
| | |
| | mutable borrow occurs here
| mutable borrow later used by call
The important difference to your desugared version is the evaluation order. The arguments of a function call are evaluated left to right in the order listed, before actually making the function call. In this case this means that first &mut v is evaluated, mutably borrowing v. Next, Index::index(&v, 1) should be evaluated, but this is not possible – v is already mutably borrowed. Finally, the compiler shows that the mutable reference is still needed for the function call to index_mut(), so the mutable reference is still alive when the shared reference is attempted.
The version that actually compiles has a slightly different evaluation order.
*v.index_mut(*v.index(1)) = 999;
First, the function arguments to the method calls are evaluated left to right, i.e. *v.index(1) is evaluated first. This results in a usize, and the temporary shared borrow of v can be released again. Then, the receiver of index_mut() is evaluated, i.e. v is mutably borrowed. This works fine, since the shared borrow has already been finalised, and the whole expression passes the borrow checker.
Note that the version that compiles only does so since the introduction of "non-lexical lifetimes". In earlier versions of Rust, the shared borrow would live until the end of the expression and result in a similar error.
The cleanest solution in my opinion is to use a temporary variable:
let i = v[1];
v[i] = 999;

What does "cannot borrow as immutable because it is also borrowed as mutable" mean in an nested array index?

What does the error mean in this case:
fn main() {
let mut v: Vec<usize> = vec![1, 2, 3, 4, 5];
v[v[1]] = 999;
}
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:3:7
|
3 | v[v[1]] = 999;
| --^----
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
I found that indexing is implemented via the Index and IndexMut traits and that v[1] is syntactic sugar for *v.index(1). Equipped with this knowledge, I tried to run the following code:
use std::ops::{Index, IndexMut};
fn main() {
let mut v: Vec<usize> = vec![1, 2, 3, 4, 5];
*v.index_mut(*v.index(1)) = 999;
}
To my surprise, this works flawlessly! Why doesn't the first snippet work, but the second one does? The way I understand the documentation, they should be equivalent, but this obviously isn't the case.
The desugared version is slightly different than what you have. The line
v[v[1]] = 999;
actually desugars to
*IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
This results in the same error message, but the annotations give a hint as to what's happening:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:7:48
|
7 | *IndexMut::index_mut(&mut v, *Index::index(&v, 1)) = 999;
| ------------------- ------ ^^ immutable borrow occurs here
| | |
| | mutable borrow occurs here
| mutable borrow later used by call
The important difference to your desugared version is the evaluation order. The arguments of a function call are evaluated left to right in the order listed, before actually making the function call. In this case this means that first &mut v is evaluated, mutably borrowing v. Next, Index::index(&v, 1) should be evaluated, but this is not possible – v is already mutably borrowed. Finally, the compiler shows that the mutable reference is still needed for the function call to index_mut(), so the mutable reference is still alive when the shared reference is attempted.
The version that actually compiles has a slightly different evaluation order.
*v.index_mut(*v.index(1)) = 999;
First, the function arguments to the method calls are evaluated left to right, i.e. *v.index(1) is evaluated first. This results in a usize, and the temporary shared borrow of v can be released again. Then, the receiver of index_mut() is evaluated, i.e. v is mutably borrowed. This works fine, since the shared borrow has already been finalised, and the whole expression passes the borrow checker.
Note that the version that compiles only does so since the introduction of "non-lexical lifetimes". In earlier versions of Rust, the shared borrow would live until the end of the expression and result in a similar error.
The cleanest solution in my opinion is to use a temporary variable:
let i = v[1];
v[i] = 999;

Understanding immutable borrows in loops

I can't quite understand why this compiles:
fn main() {
let mut v = vec![1,2,3];
for i in 1..v.len() {
v[i] = 20;
}
}
...and this doesn't:
fn main() {
let mut v = vec![1,2,3];
for (i,_) in v.iter().enumerate() {
v[i] = 20;
}
}
Error:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:6:13
|
4 | for (i,_) in v.iter().enumerate() {
| --------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
5 |
6 | v[i] = 20;
| ^ mutable borrow occurs here
In both cases we make an immutable borrow (one when call len(), other when we call iter()).
Thus, my expectation was that the 1st snippet should NOT compile -- we're making an mutable borrow when doing the assignment, when an immutable borrow exists.
What am I misunderstanding?
You are not actually making an immutable borrow in the first case, or rather, it ends after the call to len() returns (as len returns a primitive type not holding a reference to what it was used on). This means that your loop is perfectly fine, since you hold the one and only mutable object.
On the second one, you are creating a type that implements Iterator<Item = &u32> and then iterating on that iterator. The iterator has an immutable borrow to your collection (how else could you call next() on it otherwise?). This is a bit hidden, but that's where the immutable borrow is and why you cannot do what you did.
Typically, when working with iterators, and when you need to modify an element being iterated on, iter_mut is the way to go, for obvious reasons :-)

Resources