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

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.

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?

Using the same lifetime for the pointer and the lifetime parameter of the struct it points to

Consider the following:
struct Str<'a> {
s: &'a str,
}
fn f1<'a>(_: &'a mut Str<'a>) {}
fn f2<'a, 'b>(_: &'a mut Str<'b>) {}
fn main() {
let s = "hello".to_string();
let mut a = Str {
s: &s,
};
f1(&mut a);
// f2(&mut a);
let t: &Str = &a;
}
f2 uses two different lifetimes, as it would when I elided them, which works fine.
At this point, I thought that the lifetime 'a refers to the lifetime of &mut a, and 'b refers to the lifetime of &s.
And then I wrote f1 which uses a single lifetime parameter, suspecting that lifetime 'a would refer to the shorter of the lifetime of &mut a and the lifetime of &s.
However, this f1 fails with the following error:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:21:19
|
18 | f1(&mut a);
| ------ mutable borrow occurs here
...
21 | let t: &Str = &a;
| ^^
| |
| immutable borrow occurs here
| mutable borrow later used here
The error confuses me: Why is a still borrowed as mutable after calling f1?
Why does this fail, and what does the error message supposed to mean?
Why is a still borrowed as mutable after calling f1?
fn main() {
// scope of s ---\
let s = "hello".to_string(); // |
let mut a = Str { // |
s: &s, // |
}; // |
// |
// f1 borrows a until ---\ |
f1(&mut a); // | |
// but it's used here \ | |
let t: &Str = &a; // X // | |
// X X
}
The scope of s is until the end of main. Due to the lifetime annotations on f1's arguments, the mutable reference &mut a has its lifetime tied to the scope of s, which means that f1 is borrowing a for the entire scope of s.
This is not a problem with immutable references because longer lifetimes may be coerced to shorter ones; in other words lifetimes of immutable references are covariant. But lifetimes of mutable references are invariant. That means they cannot be coerced to shorter (or longer) lifetimes.

Mutable borrow goes out of scope but can't re-borrow

I'm having trouble understanding why I can't use v a second time, when it seems that the first mutable borrow has gone out of scope:
fn get_or_insert(v: &mut Vec<Option<i32>>, index: usize, default: i32) -> &mut i32 {
if let Some(entry) = v.get_mut(index) { // <-- first borrow here
if let Some(value) = entry.as_mut() {
return value;
}
}
// error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
while v.len() <= index { // <-- compiler error here
v.push(None);
}
// error[E0499]: cannot borrow `*v` as mutable more than once at a time
let entry = v.get_mut(index).unwrap(); // <-- compiler error here
*entry = Some(default);
entry.as_mut().unwrap()
}
playground link
Do I have my variable scopes wrong, or is the borrow checker protecting me from something I'm not seeing?
Edit: the error message with NLL enabled is pretty good:
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
--> src/main.rs:10:11
|
3 | fn get_or_insert(v: &mut Vec<Option<i32>>, index: usize, default: i32) -> &mut i32 {
| - let's call the lifetime of this reference `'1`
4 | if let Some(entry) = v.get_mut(index) {
| - mutable borrow occurs here
5 | if let Some(value) = entry.as_mut() {
6 | return value;
| ----- returning this value requires that `*v` is borrowed for `'1`
...
10 | while v.len() <= index {
| ^ immutable borrow occurs here
The key point is that, even with NLL, the lifetime of the return value spans the whole function. The fact that the function returns early on line 4 is not taken into account when deciding whether the v reference is accessible in the code lower down.
The fix suggested by #Stargateur is to grow the vector if needed before accessing an element:
fn get_or_insert(v: &mut Vec<Option<i32>>, index: usize, value: i32) -> &mut i32 {
if v.len() < index {
v.resize(index + 1, None);
}
v[index].get_or_insert(value)
}
playground link
Here's where I used the technique in the final code.

Why doesn't the lifetime of a mutable borrow end when the function call is complete?

I'm writing a bot for halite.io, and am having issues understanding some of the effects of borrowing. Here is the code that will not compile:
let scanLoc = hlt::types::Location {
x: oflow(coord.0 + l.x as i32, game_map.width),
y: oflow(coord.1 + l.y as i32, game_map.width),
};
let scan = game_map.get_site(scanLoc, types::STILL);
if (&scan.owner != id) | (scan.owner != 0u8) {
let ang = game_map.get_angle(l, scanLoc);
debug!("angle b/w: {}", ang);
return (l, 2);
}
This is the compiler error:
error[E0502]: cannot borrow `*game_map` as immutable because it is also borrowed as mutable
--> src/MyBot.rs:112:27
|
110 | let scan = game_map.get_site(scanLoc, types::STILL);
| -------- mutable borrow occurs here
111 | if (&scan.owner != id) | (scan.owner != 0u8) {
112 | let ang = game_map.get_angle(l, scanLoc);
| ^^^^^^^^ immutable borrow occurs here
...
116 | }
| - mutable borrow ends here
This is the code for the GameMap functions and struct:
#[derive(Clone, Debug)]
pub struct GameMap {
pub width: u16, // Number of columns.
pub height: u16, // Number of rows.
pub contents: Vec<Vec<Site>>,
}
impl GameMap {
pub fn in_bounds(&self, l: Location) -> bool {
// ...
}
pub fn get_distance(&self, l1: Location, l2: Location) -> u16 {
// ...
}
pub fn get_angle(&self, l1: Location, l2: Location) -> f64 {
// ...
}
pub fn get_location(&self, l: Location, d: u8) -> Location {
// ...
}
pub fn get_site(&mut self, l: Location, d: u8) -> &mut Site {
// ...
}
}
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Editor's note: This specific problem has been solved by the introduction of non-lexical lifetimes.
Let's look at a tiny reproduction:
struct Site {
owner: u8,
}
struct GameMap {
site: Site,
}
impl GameMap {
fn do_anything(&self) {}
fn get_site(&mut self) -> &mut Site {
&mut self.site
}
}
fn main() {
let mut game_map = GameMap {
site: Site { owner: 0 },
};
let site = game_map.get_site();
game_map.do_anything();
}
error[E0502]: cannot borrow `game_map` as immutable because it is also borrowed as mutable
--> src/main.rs:22:5
|
21 | let site = game_map.get_site();
| -------- mutable borrow occurs here
22 | game_map.do_anything(); // Compiler error!
| ^^^^^^^^ immutable borrow occurs here
23 | }
| - mutable borrow ends here
Our GameMap only owns a single Site, but that's enough. The call to get_site returns a reference (in this case it happens to be mutable):
fn get_site(&mut self) -> &mut Site
Thanks to lifetime elision, this is the same as
fn get_site<'a>(&'a mut self) -> &'a mut Site
This means that the returned reference is allowed to point to something inside of GameMap (which it does). Then we keep that reference in a variable - site!
That means that we can no longer use any immutable references to game_map as they might have been (or will in the future be) invalidated by the changes that can be made to the map through the mutable reference:
At any given time, you can have either one mutable reference or any number of immutable references.
References must always be valid.
— The Rust Programming Language chapter on references and borrowing
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Rust borrows your struct mutably because you are calling a method that requires a mutable reference (&mut self). That method then returns a mutable reference, transferring the borrow of the struct to the returned value. The borrow ends when the returned value goes out of scope.
So, how do you fix it? Probably the most flexible solution is to introduce a scope to constrain the mutable borrow:
let zhu_li_do_the_thing = {
let site = game_map.get_site();
site.owner == 5 || site.owner == 42
};
if zhu_li_do_the_thing {
game_map.do_anything();
}
Another is the same idea, but requires that you never store the borrow in a variable at all. Thus the mutable borrow doesn't last beyond that statement:
if game_map.get_site().owner == 42 {
game_map.do_anything();
}
It's common for idiomatic Rust code to have foo and foo_mut variants of a method, for when you don't need mutability. This may not help if you need to mutate game_map while the immutable borrow of site is still outstanding.
fn get_site(&self) -> &Site {
&self.site
}
fn get_site_mut(&mut self) -> &mut Site {
&mut self.site
}
let site = game_map.get_site();
if site.owner == 5 || site.owner == 42 {
game_map.do_anything();
}
See also:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
What are non-lexical lifetimes?

Resources