This question already has an answer here:
Why does the Rust compiler error with "cannot borrow as immutable because it is also borrowed as mutable" after moving the variable into a scope?
(1 answer)
Closed 1 year ago.
The Rust Book says
"you can have only one mutable reference to a particular piece of data in a particular scope"
As far as I can tell, the following working code contradicts this by having 2 simultaneous mutable references:
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
}
The code is just a slight modification to this example from the book:
fn main() {
let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1 goes out of scope here, so we can make a new reference with no problems.
let r2 = &mut s;
}
The book implies that it's only possible to make the 2nd mutable reference because the first one went out of scope, but when I modified the code so that the first reference does not go out of scope, it still compiles. Why is this allowed? I thought Rust was only supposed to allow 1 mutable reference at a time.
The r1 is still in scope, but you won't be able to use it. That's because it borrowed s. But once r2 borrowed it, r1 is no more use-able.
For example, try adding
dbg!(r1);
You should get an error:
|
15 | let r1 = &mut s;
| ------ first mutable borrow occurs here
16 | let r2 = &mut s;
| ^^^^^^ second mutable borrow occurs here
17 |
18 | dbg!(r1);
| -- first borrow later used here
Related
I am noob to Rust and wanted to solidify my understanding of mutable reference in Rust.
fn mutate_me(st: &mut String)-> usize {
st.push_str(" mutated.");
st.len()
}
When I try using any one of either x or mutable reference r1 there is no compilation error.
fn main() {
let mut x = String::from("random");
let r1 = &mut x;
println!("{}", x);
}
This also work without any compilation error.
fn main() {
let mut x = String::from("random");
let r1 = &mut x;
println!("{}", mutate_me(r1));
}
But the one below fails as I tried using both of them.
fn main() {
let mut x = String::from("random");
let r1 = &mut x;
println!("{}", mutate_me(r1));
println!("{}", x);
println!("{}", *r1);
}
Does this imply that for mutable reference, whichever tried using it next first becomes valid and the other one invalid?
As a complement to #ChayimFriedman answer. Usually (not always) you have to work around the borrowing and flow of your program using scopes, so that things are used and dropped to liberate outer ones. For example your third case could be transformed as follows:
fn main() {
let mut x = String::from("random");
let res = {
let r1 = &mut x;
println!("{}", r1);
mutate_me(r1)
};
println!("{}", res);
println!("{}", x);
}
Playground
From the moment you borrow something to the last usage of the reference, the reference is considered alive for borrowing. Accessing an object while a mutable reference to it is alive is an error.
In your first example, you don't use r1 (it is immediately dropped), so the region of code where you can use x is between the two statements let r1 = &mut x; and let r1 = &mut x;, meaning... zero code.
In the second example you never use x, so in the code region x is invalid to use - between the declaration of r1 and its use - x is never actually used. Everything is fine.
The problem is in the third example, when you use x in the "invalid range". You can remove the println!("{}", mutate_me(r1)); - it doesn't matter.
The compiler points on these three important points: where the reference was created, when it's being used later, and where you perform the invalid access (this is called the "three-points models" in the NLL RFC):
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> src/main.rs:4:20
|
3 | let r1 = &mut x;
| ------ mutable borrow occurs here
4 | println!("{}", x);
| ^ immutable borrow occurs here
5 | println!("{}", *r1);
| --- mutable borrow later used here
Playground.
Why does the following fail to compile (2018 edition)
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
{
let _r2 = &s;
}
println!("{}", r1);
}
Why the compiler fails to notice that _r2 is unused and successfully compile the above?
It complains that we have both mutable and immutable refs and mutable is used in println.
the confusing part is that literature (books etc...) talk about "using block to restrict borrowing scope. "Beginning Rust" p348 for example. So I found it confusing that we advocate for such practices but it (sometimes) does not work.
But it does work here; the scope of _r2 is restricted by the block it's
declared in. The problem is just that r1 is visible in this scope as well.
That is, the error message is not saying "you can't println because there are both mutable and immutable borrows at that point", but "you can't declare _r2 because there is already a mutable borrow at that point". println only appears as a reason why r1 is still alive at the point of _r2's declaration.
You can see it from the error message:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> src/main.rs:5:19
|
3 | let r1 = &mut s;
| ------ mutable borrow occurs here
4 | {
5 | let _r2 = &s;
| ^^ immutable borrow occurs here
6 | }
7 | println!("{}", r1);
| -- mutable borrow later used here
^^ points at the actual error location; -- are other related locations.
You can only do like this,
fn main(){
let mut s = String::from("hello");
let r1 = &mut s;
{
let r2 = &r1;
}
println!("{}", r1);
}
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
This question already has an answer here:
Error while trying to borrow 2 fields from a struct wrapped in RefCell
(1 answer)
Closed 3 years ago.
Trying to get mutable references to separate fields through a MutexGuard:
struct MyObject {
pub a: i32,
pub b: i32,
}
fn func_1(mtx: &Mutex<MyObject>) {
let mut obj = mtx.lock().unwrap();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
results in an error:
error[E0499]: cannot borrow `obj` as mutable more than once at a time
--> src/main.rs:11:18
|
10 | let a = &mut obj.a;
| --- first mutable borrow occurs here
11 | let b = &mut obj.b;
| ^^^ second mutable borrow occurs here
12 |
13 | *a += 1;
| ------- first borrow later used here
This has me a bit confused. This works when obj is a simple mutable reference (&mut MyObject). I thought maybe the Deref trait was the one causing the problem, but it also works if obj is a &mut Box<MyObject>.
See it on the Rust Playground.
What am I missing?
Mutex::lock returns a RAII lock guard in addition of ways to deal with its contained value. To get its contained value as &mut (and subsequently "split borrow"), you need to:
save the guard (returned by lock) in a separate value, as the lock needs to live as long as the value is accessed.
extract the value as &mut from the guard with MutexGuard::deref_mut.
Here's an updated func_1:
use std::ops::DerefMut;
fn func_1(mtx: &Mutex<MyObject>) {
let mut guard = mtx.lock().unwrap();
let obj = guard.deref_mut();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
This question already has an answer here:
What are non-lexical lifetimes?
(1 answer)
Closed 2 years ago.
I am checking out this rust doc
https://doc.rust-lang.org/1.30.0/book/2018-edition/ch04-02-references-and-borrowing.html
I will not see any error when I borrowed &mut twice (see the code below), can anyone tell me why?
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
This is due to non-lexical lifetimes. The compiler recognizes that, since the first reference is never used after the second is created (or at all, in your example), it can simply be dropped, allowing the second reference to be created.
If we attempt to extend the lifetime of the first reference with the below example, we'll get an error about having multiple mutable references, as expected:
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s; // error[E0499]: cannot borrow `s` as mutable more than once at a time
drop(r1);