Understanding immutable borrows in loops - rust

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 :-)

Related

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;

How can I give names to Rust slices without taking ownership?

In the context of a crypto problem, to decrease verbosity, I'm "naming" a slice of v as block, doing some stuff to it, but then trying to verify the result of do_stuff on the whole of v:
fn x() {
let mut v = vec![0; 32];
let block = &mut v[0..16];
do_stuff(block);
check_stuff(&v);
do_stuff(block);
}
fn do_stuff(_: &mut [i32]) {}
fn check_stuff(_: &[i32]) {}
The borrow checker complains:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/lib.rs:6:17
|
3 | let block = &mut v[0..16];
| - mutable borrow occurs here
...
6 | check_stuff(&v);
| ^^ immutable borrow occurs here
7 | do_stuff(block);
| ----- mutable borrow later used here
I'm aware of the kind of guarantee this is trying to provide. However, assuming I know what I'm doing, is there an idiomatic way to give a name to the slice without having to use do_stuff(&mut v[0..16]) or having to make copies every time?

Why does Rust want to borrow a variable as mutable more than once at a time?

I'm attempting to implement a dynamic programming problem in Rust to gain familiarity with the language. Like many dynamic programming problems, this uses memoization to reduce the running time. Unfortunately, my first-pass solution yields errors. I've pared the code down to the following. Warning - it's now a bit nonsensical:
use std::collections::HashMap;
fn repro<'m>(memo: &'m mut HashMap<i32, Vec<i32>>) -> Option<&'m Vec<i32>> {
{
let script_a = repro(memo);
let script_b = repro(memo);
}
memo.get(&0)
}
fn main() {}
The compilation error is:
error[E0499]: cannot borrow `*memo` as mutable more than once at a time
--> src/main.rs:6:30
|
5 | let script_a = repro(memo);
| ---- first mutable borrow occurs here
6 | let script_b = repro(memo);
| ^^^^ second mutable borrow occurs here
7 | }
| - first borrow ends here
Why is the variable memo borrowed multiple times? In my view, it should be borrowed once when I compute script_a, then that borrow ends, then it gets borrowed again for script_b.
Currently borrows last for the block they are defined in (#9113 might change this if implemented)
The problem is that script_a (that holds an immutable reference to a map) is valid for the whole block and you try to use a mutable reference to the same map:
let script_a = repro(memo);
let script_b = repro(memo);
// script_a is still alive
The bigger problem is the infinite loop. Anyway let script_a is a reference to data inside the hash map, so it's still borrowed by the time you call let script_b = repro(memo);.

Resources