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.
Related
I have a function which takes a Vec and pushes zero or more elements to it. The Vec and the reference passed to the function are both mut. When I try to get the length of the Vec upon return (to see how many elements were pushed), I get the dreaded "cannot borrow 'foo' as immutable because it is also borrowed as mutable" error.
In general, I get why this error exists in general. I don't get why it's necessary here.
Surely there's a way to do this -- I can't be the first person who has tried something like this.
Here's a stripped-down version of what I'm trying to do, that replicates the error.
fn main() {
let mut stack = vec!["one"];
push(&mut stack, "two");
}
fn push<'a>(stack: &'a mut Vec<&'a str>, value: &'a str) {
stack.push(value);
}
#[test]
fn test_len() {
let mut stack = vec!["one"];
push(&mut stack, "two");
assert_eq!(stack.len(), 2);
}
error[E0502]: cannot borrow `stack` as immutable because it is also borrowed as mutable
--> src/main.rs:14:16
|
13 | push(&mut stack, "two");
| ---------- mutable borrow occurs here
14 | assert_eq!(stack.len(), 2);
| ^^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
Don't force the references lifetime and the lifetime of the mutable borrow to be the same.
fn push<'a>(stack: &mut Vec<&'a str>, value: &'a str) {
stack.push(value);
}
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.
I have a struct UI holding a mutable reference to Stdout. Instead of mutating it on update, I'd prefer to replace it with an entirely new UI:
use std::io::{stdout, Result, Stdout, Write};
struct UI<'s> {
stdout: &'s mut Stdout,
v: Box<()>, // If remove this field, the error goes away.
}
impl<'s> UI<'s> {
fn new(stdout: &'s mut Stdout) -> Result<Self> {
let ui = UI {
stdout: stdout,
v: Box::new(()),
};
Ok(ui)
}
fn write(&mut self) -> Result<()> {
write!(self.stdout, "heyyyyy")?;
self.stdout.flush()?;
Ok(())
}
}
fn main() -> Result<()> {
let mut stdout = stdout();
let mut ui = UI::new(&mut stdout)?;
ui = UI::new(&mut stdout)?;
ui.write()?; // If you comment this line out, the error goes away.
Ok(())
}
playground
The borrow checker complains that stdout is borrowed mutably twice:
error[E0499]: cannot borrow `stdout` as mutable more than once at a time
--> src/main.rs:30:18
|
28 | let mut ui = UI::new(&mut stdout)?;
| ----------- first mutable borrow occurs here
29 |
30 | ui = UI::new(&mut stdout)?;
| -- ^^^^^^^^^^^ second mutable borrow occurs here
| |
| first borrow might be used here, when `ui` is dropped and runs the destructor for type `UI<'_>`
There are two weird behaviors:
If I remove field v, the error goes away.
If I remove ui.display()?, the error also goes away.
What's the problem here?
Addressing #kmdreko's suggestion:
The first point is explained in the error message, albeit in a roundabout way if you don't know what's going on. Box implements Drop, so that it can deallocate its contents when destroyed; and therefore UI automatically implements Drop, which means there is code executed which could access stdout between reborrowing it for a new UI and assigning it to ui.
Then why does this return an error?
fn main() -> Result<()> {
let mut stdout = stdout();
let mut ui = UI::new(&mut stdout)?;
for _ in 0..10 {
drop(ui);
ui = UI::new(&mut stdout)?;
ui.write()?;
}
Ok(())
}
error[E0499]: cannot borrow `stdout` as mutable more than once at a time
--> src/main.rs:33:22
|
28 | let mut ui = UI::new(&mut stdout)?;
| ----------- first mutable borrow occurs here
...
33 | ui = UI::new(&mut stdout)?;
| -- ^^^^^^^^^^^ second mutable borrow occurs here
| |
| first borrow might be used here, when `ui` is dropped and runs the destructor for type `UI<'_>`
Someone on Reddit suggested to implement take(self) -> &'s mut Stdout for UI and it works, but I have no idea why. Playground.
When replacing a value, the new value must be created first:
struct Noisy(u8);
impl Noisy {
fn new(v: u8) -> Self {
eprintln!("creating {}", v);
Self(v)
}
}
impl Drop for Noisy {
fn drop(&mut self) {
eprintln!("dropping {}", self.0);
}
}
fn main() {
let mut ui = Noisy::new(1);
ui = Noisy::new(2);
}
creating 1
creating 2
dropping 1
dropping 2
This means that your two UI structs would attempt to coexist. Since they both have a mutable reference to stdout, the Drop::drop implementation might mutate stdout, which would violate the rules of references as there would be multiple active mutable references at one point.
When you don't call write, the non-lexical borrow checker sees that the borrow isn't needed, so there's no problem.
Then why does [explicitly dropping the value before reassigning it] return an error?
Because that is a limitation of the current borrow checker implementation.
See also:
What are non-lexical lifetimes?
Why does linking lifetimes matter only with mutable references?
Does Rust free up the memory of overwritten variables?
Moved variable still borrowing after calling `drop`?
What are the options to end a mutable borrow in 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
}
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?