I created two example codes, one using references of a Box and the other using borrow_mut of a RefCell and they don't work the same, to my surprise.
use std::cell::RefCell;
#[derive(Debug)]
struct A {
a: usize,
}
fn main() {
let m;
let mut n = Box::new(A{a:5});
{let a = &mut n; m = &mut a.a;}
*m = 6;
println!("{}", m);
println!("{:?}", n);
let mm;
let mut nn = RefCell::new(A{a:5});
{let mut aa = nn.borrow_mut(); mm = &mut aa.a;}
*mm = 6;
println!("{:?}", mm);
println!("{:?}", nn);
}
I'm getting an error saying the aa borrowed value does not live long enough. &mut aa.a should be &mut usize so nothing to do with a RefCell and should work just like the Box example. Why am I getting this error?
The problem is that while the borrow &mut n is just a pure reference, nn.borrow_mut() is not. It returns a RefMut that implements Drop - because it needs to mark the RefCell as no longer borrowed after it is dropped. Therefore, the compiler can extend the lifetime of &mut n as it doesn't do anything when dropped, but it cannot do so for nn.borrow_mut() because it alters the behavior of the program.
Related
this is simple code which shows error cannot assign to a because it is borrowed assi gnment to borrowed a occurs here. Can it be possible to assign value if it is borrowed?
fn main() {
let mut a = 20;
let b = &a;
a = 20;
println!("{}, {}", a, b);
}
Not without interior mutability.
Disallowing mutation of a value that is borrowed prevents many different kinds of bugs. For example, you cannot push onto a Vec while you have a shared reference to a value in the Vec. This seems arbitrary, but if pushing causes an internal reallocation, previously-dispensed references would become dangling.
Here's what the interior mutability approach would look like:
use std::cell::Cell;
fn main() {
let a = Cell::new(20);
let b = &a;
a.set(10);
println!("{}, {}", a.get(), b.get());
}
Note a doesn't even have to be declared mut, because cells can be mutated through a shared reference.
Rust enforces "multiple readers or single writer" rule at compile time. As long as there is mutable reference to a value you cannot use the owner until the mutable reference goes away. Similarly as long as there is multiple shared references to value not even it's owner can modify it. For example, this would compile.
fn main() {
let mut a = 20;
{
let b = &a;
println!("{}", b);
} // Shared reference goes out of scope here
a = 20;
println!("{}", a);
}
This code doesn't compile. But it fails on the last line marked Err, not the line marked Ok. Why can we assign a mutable reference to an immutable reference type but not use it after the assignment?
fn main() {
let mut x = 10;
let mut y = 20;
let mut r = &x;
r = &mut y; //Ok
*r = 30; //Err
}
Why can we ... not use it after the assignment?
The variable r is an immutable reference of type &i32; it does not have mutable access to the referenced value. So it makes sense the compiler would reject your attempt to assign through it.
Why can we assign a mutable reference to an immutable reference type ...?
Why wouldn't you be able to downgrade a mutable reference into an immutable one? The latter is a strict subset of the former. If you were asking about the technicalities instead of the practicalities, its because &mut T to &T is a supported coercion.
If we add explicit types to your code as inferred by the compiler:
fn main() {
let mut x: i32 = 10;
let mut y: i32 = 20;
let mut r: &i32 = &x;
r = &mut y; //Ok
*r = 30; //Err
}
We see that r has type &i32 and not &mut i32, so of course we can't use r to modify the referenced value.
Why can we still do r = &mut y? Simply because we can always use a &mut reference anywhere a & reference is expected (because &mut T implements Deref<Target=T>, allowing coercion to happen).
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.
I am learning Rust and I've run into some confusing behaviour. The following code compiles fine and works as expected (edit: added code other than test function, previously omitted):
struct Container<'a> {
contents : &'a mut i32,
}
fn main() {
let mut one = Container { contents: &mut 5 };
test(&mut one);
println!("Contents: {}",one.contents);
}
fn test<'a>(mut x : &'a mut Container) {
*x.contents += 1;
let y = x;
*y.contents += 1;
x = y;
println!("{:?}",*x.contents)
}
Now in the statement
let y = x;
the type is inferred. Because x is of type &'a mut Container, I thought that this would be equivalent:
let y: &'a mut Container = x;
But when I do that, the compiler takes issue:
test_3.rs:25:5: 25:10 error: cannot assign to `x` because it is borrowed
test_3.rs:25 x = y;
^~~~~
test_3.rs:23:33: 23:34 note: borrow of `x` occurs here
test_3.rs:23 let y: &'a mut Container = x;
How is x not borrowed by that point in the correctly working example? I tested by omitting the line x = y; from the correctly working version and the compiler said:
test_3.rs:24:13: 24:14 note: `x` moved here because it has type `&mut Container<'_>`, which is moved by default
So I'm getting a move when I don't explicitly define the type but a borrow otherwise. What is going on, how do I get the same behavior as before while explicitly giving the type, and what is causing move behavior in one case but borrow in the other?
Edited with full program
When you do
let y = x;
a move happens. x is emptied, so to speak, and ownership is transferred to y.
When you do either of
let y: &mut _ = x;
let y: &'a mut _ = x;
x is reborrowed to aid matching the lifetimes. This roughly translates to
let y: &mut _ = &mut *x;
let y: &'a mut _ = &mut *x;
This leaves x non-empty, holding an aliased mutable borrow. Assigning to it thus must wait for y to be destroyed. Alternatively, you can pre-move it
let tmp = x;
let y: &'a mut _ = tmp;
I'll admit it's nonobvious behaviour, and it's a shame that you can't borrow the contents of a value without borrowing the whole value.
Why does the compiler reject this code:
struct S<'a> {
i: i32,
r: &'a i32,
}
fn main() {
let mut s = S{i: 0, r: &0};
{
let m1 = &mut s;
m1.r = &m1.i;
}
let m2 = &mut s;
}
The error is: "cannot borrow s as mutable more than once at a time" (first borrow: m1, second borrow: m2).
Why is the first borrow of s still alive after m1 goes out of scope?
I read about borrow scope extension beyond the scope of the original borrower. However, this always seemed to involve another borrower outside the scope of the original borrower that "took over" the original borrow, e.g. this code fails with the exact same error, which is clear to me:
fn main() {
let mut s = 0;
let r: &mut i32;
{
let m1 = &mut s;
r = m1;
}
let m2 = &mut s;
}
In the first example, if I replace m1.r = &m1.i; with m1.r = &dummy; (dummy defined as some &i32) or with let dummy = &m1.i;, the code compiles. The error occurs only if I store a reference to a field in another field of the borrowed struct. I don't see why this should extend the borrow beyond its scope.
My best guess as to what is wrong with the code is:
s.r's original lifetime is the whole of main,
when I assign a reference to m1.r it has to be that original lifetime, but &m1.i is only valid for as long as m1 lives.
But I might be wrong (the error message would be misleading then).
First note that
let mut s = S{i: 0, r: &0};
{
s.r = &s.i;
}
let m2 = &mut s;
Gives
cannot borrow `s` as mutable because `s.i` is also borrowed as immutable
Hopefully this should be clear - if a struct self-borrows then it is borrowed. This points out why any self-borrowing structure is basically useless - it cannot be moved (invalidating its own pointer) nor can and mutable reference be taken to it.
Next one needs to understand that immutable references from mutable references count as borrows into the mutable reference, so extend it. For example
let mut v = ();
let r1 = &(&mut v);
let r2 = &v;
gives
cannot borrow `v` as immutable because it is also borrowed as mutable
It's not clear if this is legally able to be a new borrow into the original structure, but it as-yet does not act as such.