Trouble understanding immutable and mutable borrows in vector indexing operations - rust

I just started out with Rust. I have some trouble understanding mutable and immutable borrows with respect to this snippet of code. Here is the code I am testing.
fn main() {
let mut list = vec![1,2,3,4,5,6];
let i = 2;
list[list[i]] = list[list[i-1]];
}
On compiling this, I get the following error:
error[E0502]: cannot borrow `list` as immutable because it is also borrowed as mutable
--> src/main.rs:4:7
|
4 | list[list[i]] = list[list[i-1]];
| -----^^^^----
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
error: aborting due to previous error
When I replace the snippet above with this code instead,
fn main() {
let mut list = vec![1,2,3,4,5,6];
let i = 2;
let index = list[i];
list[index] = list[list[i-1]];
}
the code compiles and executes fine.
My question is why is the compiler not flagging this as an error like this?
5 | list[index] = list[list[i-1]];
| --------------| |
| | | immutable borrow occurs here
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
Isin't the right hand side of the assignment an immutable borrow? Why only flag the first code snippet as an error?
Does Rust have something like happens-before or sequenced before relationship in C++ which ensures that the immutable borrow on the right hand side is sequenced before the mutable borrow on the left hand side and hence it is not an error?
If the answer to the previous question is yes, then why can't the compiler sequence list[list[i]] internally as let tmp = list[i]; list[tmp]=...?

Here is some code that demonstrates the same issue, but a bit simplified.
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
let place: &mut usize = &mut list[list[i]];
*place = 3;
}
Evidently, the compiler is doing something like this:
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
// mutable borrow of list starts
let r: &mut Vec<usize> = &mut list;
// immutable borrow of list starts
let q: usize = list[i];
// immutable borrow of list ends
// mutable borrow of r starts
let place: &mut usize = &mut r[q];
// place is a mutable borrow derived from r
*place = 3;
// place is dropped, mutable borrow of r ends
// r is dropped, mutable borrow of list ends
}
This code works fine:
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
let q: usize = list[i]; // immutable borrow begins and ends
let place: &mut usize = &mut list[q]; // mutable borrow begins
*place = 3; // mutable borrow ends
}

Related

cannot borrow `var` as immutable because it is also borrowed as mutable

While trying to compile the following code, im getting an error:
error[E0502]: cannot borrow var as immutable because it is also borrowed as mutable
fn increment(num : &mut i32){
*num = *num +1;
}
fn main() {
let mut var : i32 = 123;
let p_var: &mut i32 = &mut var;
println!("{}", var);
increment(p_var);
}
I have no clue what does it mean, can someone explain me exacly why am I getting this error?
fn increment(num: &mut i32){
*num = *num +1;
}
fn main() {
let mut var : i32 = 123;
println!("{}", var);
increment(&mut var);
println!("{}", var);
}
worked for me.
I, myself, am a Rust beginner, too. So, here is what my view on this is ( I MAY be utterly wrong ):
In this code var never gives up ownership and has no mutable borrows that are still in scope when it borrows immutably. I therefore can borrow it mutably to the increment function. After it has returned that borrow is not alive anymore. I therefore can borrow var` again to the println macro.
When you assigned to p_var you created a mutable borrow that was in scope and alive when you tried to borrow to the println macro, which is not allowed.
This is what the incredible cargo told me:
error[E0502]: cannot borrow `var` as immutable because it is also borrowed as mutable
--> src/main.rs:9:20
|
7 | let p_var : &mut i32 = &mut var;
| -------- mutable borrow occurs here
8 |
9 | println!("{}", var);
| ^^^ immutable borrow occurs here
10 | increment(p_var);
| ----- mutable borrow later used here
|
It would be great if some more experienced rustacian could verify (or correct) my reasoning and assessment.
It's not possible due to Rust mutable reference rules.
Until there is a mutable reference is alive in a lifetime scope, the only way to access that referent is the that alive reference.
In your case you already have p_var alive, so the only way to access it is through p_var. Hence you are violating the rust mutable reference rules.
For example this works:
fn increment(num : &mut i32){
*num = *num +1;
}
fn main() {
let mut var : i32 = 123;
{
let p_var: &mut i32 = &mut var;
increment(p_var);
}
println!("{}", var);
}
This works because println!("{}", var) ran, p_var life time has already ended. If you try to reference var inside the {} scope it won't work either.

Decoupling ownership from vector

I'm creating factory methods for objects with shared references. The compiler cannot see that the objects from a Vec are not referenced outside the local scope, and that the newly created objects are not linked to the original objects.
How do I get around this issue, what am I missing?
#[derive(Debug)]
pub struct A {}
pub struct B<'b> {
a: &'b A,
}
impl<'b> B<'b> {
pub fn new(a: &'b A) -> B {
B { a: a }
}
pub fn combine(&self, _: &B) -> B {
B::new(self.a)
}
}
pub fn main() {
let a: A = A {};
let mut v1: Vec<B> = vec![];
v1.push(B::new(&a));
v1.push(B::new(&a));
let mut v2: Vec<B> = vec![];
{
let b1 = &v1[0]; // << Mutable borrow occurs here - why?
let b2 = &v1[1];
let c = b1.combine(&b2);
v2.push(c)
}
v1.clear(); // Error: Cannot borrow due to mutable borrow above
println!("{:?}", v2[0].a);
}
error[E0502]: cannot borrow `v1` as mutable because it is also borrowed as immutable
--> src/main.rs:32:5
|
27 | let b1 = &v1[0]; // << Mutable borrow occurs here - why?
| -- immutable borrow occurs here
...
32 | v1.clear(); // Error: Cannot borrow due to mutable borrow above
| ^^^^^^^^^^ mutable borrow occurs here
33 | println!("{:?}", v2[0].a);
| -- immutable borrow later used here
No, sorry, I still do not quite get it.
Here is an even simpler example, without vectors:
let a:A = A { };
let mut b1 = B::new(&a);
let mut b2 = B::new(&a);
let c = &b1.combine(&b2);
// ^^^ This creates a mutable reference to b1. How to avoid?
b1 = B::new(&a);
b2 = B::new(&a);
println!("{:?}",c.a);
For some reason, the method call on the object will make the compiler assume that I have a reference to the object, despite c having no reference to b1. How do I get around that?
How can I declare the combine()-method to be immutable?

When is a reference being 'used' in non-lexical lifetimes?

struct Object {
alive: bool,
name: String,
}
impl Object {
// the comments are what I thought the compiler was supposed to give
fn test(&mut self) {
let alive = &mut self.alive; // seems like there is mutable borrow here
self.name = String::from("dead"); // another mutable borrow
*alive = false; // mutable borrow later used here
}
}
fn print(x: &Object) {
println!("Hello {:?}", x);
}
A non-lexical lifetime is supposed to be when a reference stops living after it's last use. I am confused on what that use is.
alive is a mutable borrow to self.alive and then self is used to do self.name = String::from("dead");. After this it looks like alive is used again in *alive = false. Except this code compiles.
If I change the code to this:
fn test(&mut self) {
let alive = &mut self.alive;
print(self);
self.name = String::from("dead");
*alive = false;
}
then the code gives this error
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable [10/58]
--> src/main.rs:45:15
|
44 | let alive = &mut self.alive;
| --------------- mutable borrow occurs here
45 | print(self);
| ^^^^ immutable borrow occurs here
46 | self.name = String::from("dead");
47 | *alive = false;
| -------------- mutable borrow later used here
. Does this mean that references are only 'used' when they are in functions and not when dereferenced with * or the dot notation? How does the first example compile even though it seems like the the reference scopes are overlapping?
Does this mean that references are only 'used' when they are in functions and not when dereferenced with * or the dot notation?
You are close. Non-lexical lifetimes aren't a factor here, but the borrow checker has more tricks up its sleeves. It knows that the fields of a struct are distinct objects and can be borrowed independently.
From the Rust Nomicon on Splitting Borrows:
It does understand structs sufficiently to know that it's possible to borrow disjoint fields of a struct simultaneously. So this works today:
struct Foo {
a: i32,
b: i32,
c: i32,
}
let mut x = Foo {a: 0, b: 0, c: 0};
let a = &mut x.a;
let b = &mut x.b;
let c = &x.c;
*b += 1;
let c2 = &x.c;
*a += 10;
println!("{} {} {} {}", a, b, c, c2);
So in your code, there can be exclusive references to both self.alive and self.name because borrow checker knows they aren't referencing the same object. Adding the print(self) needs to reference the whole self and conflicts with the borrow given to alive.

Cannot borrow X as immutable because it is also borrowed as mutable in a mutable closure

Here is my code, and the compiler error beneath.
fn main() {
let mut s = String::new();
let mut push_if = |b, some_str| {
if b {
s.push_str(some_str);
}
};
push_if(s.is_empty(), "Foo");
println!("{}", s);
}
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> src/main.rs:8:13
|
3 | let mut push_if = |b, some_str| {
| ------------- mutable borrow occurs here
4 | if b {
5 | s.push_str(some_str);
| - first borrow occurs due to use of `s` in closure
...
8 | push_if(s.is_empty(), "Foo");
| ------- ^ immutable borrow occurs here
| |
| mutable borrow later used by call
Why is the compiler complaining about s.is_empty() being an immutable borrow?
I'm just trying to return a bool, which doesn't seem like I'm borrowing anything. What changes do I need to make to compile the program successfully?
You can try this:
fn main() {
let mut s = String::new();
let mut push_if = |b, some_str, string: &mut String| {
if b {
string.push_str(some_str);
}
};
push_if(s.is_empty(), "Foo", &mut s);
println!("{}", s);
}

Borrow errors for multiple borrows

I am implementing an in-place recursive parser in rust and I am getting some borrow errors. The code snippet reproduces the problem although it is not very useful
use std::vec::Vec;
struct MyBorrows<'a> {
val : &'a mut i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a mut i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let mut my_val = 23;
let mut my_vec : Vec<Box<MyBorrows>> = Vec::new();
my_vec.push(Box::new(MyBorrows::new(&mut my_val)));
for i in [1..4].iter() {
let mut last : &mut Box<MyBorrows> = my_vec.last_mut().unwrap();
let mut new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
This gives me the following error:
error[E0499]: cannot borrow `my_vec` as mutable more than once at a time
--> test.rs:20:9
|
18 | let mut last : &mut Box = my_vec.last_mut().unwrap();
| ------ first mutable borrow occurs here
19 | let mut new_borrow = Box::new(MyBorrows::new(last.val));
20 | my_vec.push(new_borrow);
| ^^^^^^ second mutable borrow occurs here
21 | }
22 | }
| - first borrow ends here
error: aborting due to 3 previous errors
In my real case, the vector is used as a stack to reference deeper and deeper components of the struct I am parsing into. This is common pattern I use for general purpose parsing in C++ which I am trying to replicate in Rust but I am having problems. Any help will be appreciated.
What you are trying to do is unsound. It looks like you are attempting to create multiple MyBorrows which all mutably borrow the same value, and have them all alive at once (in the vector). Such setups are exactly what Rust is designed to prevent, as that's how data races occur.
What you might instead want to do is immutably borrow the value a bunch, which is legal. So after cleaning up the unnecessary mutable borrows, I've reduced the problem to:
struct MyBorrows<'a> {
val : &'a i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let last = my_vec.last().unwrap();
let new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
You get a slightly different error now:
error[E0502]: cannot borrow `my_vec` as mutable because it is also borrowed as immutable
--> test.rs:18:9
|
16 | let last = my_vec.last().unwrap();
| ------ immutable borrow occurs here
17 | let new_borrow = Box::new(MyBorrows::new(last.val));
18 | my_vec.push(new_borrow);
| ^^^^^^ mutable borrow occurs here
19 | }
| - immutable borrow ends here
error: aborting due to previous error
This one is trickier, and you have to realize what is going on when you call my_vec.last() -- it's returning a reference to existing memory in the Vec, precluding anything else from touching the Vec. Currently in Rust, this reference lives until the end of the current block. To get around this, encase the mutable borrow in its own block scope:
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let new_borrow;
{
let last = my_vec.last().unwrap();
new_borrow = Box::new(MyBorrows::new(last.val));
}
my_vec.push(new_borrow);
}
}
Now the mutable borrow ends before the push occurs, and the lifetimes work. Hopefully in the future, we will get non-lexical lifetimes added to the language, so the compiler can figure out that my first example is actually safe.

Resources