What's the difference between lifetimes of immutable and mutable references? [duplicate] - rust

This question already has answers here:
Why does linking lifetimes matter only with mutable references?
(2 answers)
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
(2 answers)
Closed 2 years ago.
There is a struct definition as follows.
struct Test<'a> {
t: &'a str,
}
impl<'a> Test<'a> {
pub fn shared_borrow(&'a self) {
println!("{}", self.t);
}
pub fn mutable_borrow(&'a mut self) {
println!("{}", self.t);
}
}
Case 1. It can pass through the borrowing check, if shared_borrow() is called before mutable_borrow().
fn main() {
let mut x = Test { t: "test" };
x.shared_borrow();
x.mutable_borrow();
}
Case 2. It fails if I exchange the order of the method calls as follows.
fn main() {
let mut x = Test { t: "test" };
x.mutable_borrow();
x.shared_borrow();
}
compiler's output:
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> src/main.rs:16:5
|
15 | x.mutable_borrow();
| - mutable borrow occurs here
16 | x.shared_borrow();
| ^
| |
| immutable borrow occurs here
| mutable borrow later used here
error: aborting due to previous error
As I know, shared_borrow() and mutable_borrow() both borrow x for the entire lifetime of x, because the lifetimes are explicitly declared as 'a, which is the lifetime of x.
In Case 1, x.shared_borrow() will borrow x for the entire lifetime of x. So It shouldn't be allowed to call x.mutable_borrow() after that. I'm confused why the compiler doesn't report an error as what it does in Case 2.

Related

How do I get the length of a Vec after it has been modified?

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);
}

Implementing a recursive cache in Rust [duplicate]

This question already has answers here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
When is it necessary to circumvent Rust's borrow checker?
(1 answer)
Closed 1 year ago.
use std::collections::HashMap;
#[derive(Clone, Hash, Eq, PartialEq)]
struct HeavyCloneKey;
struct Map<V> {
map : HashMap<HeavyCloneKey, V>
}
impl<V> Map<V> {
pub fn get_mut(&mut self, key: &HeavyCloneKey) -> Option<&mut V> {
if let Some(v) = self.map.get_mut(key) {
return Some(v);
}
// some logic to decide if create a new value;
if self.map.len() > 64 {
None
} else {
let v = create_v_with_long_code();
let v = self.map.entry(key.clone()).or_insert_with(|| v);
Some(v)
}
}
}
fn create_v_with_long_code<V>() -> V {
unimplemented!()
}
fn main() {
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=19c45ebfb1a39271ff5bd2443399596a
I can't understand why this can't work:
error[E0502]: cannot borrow `self.map` as immutable because it is also borrowed as mutable
--> src/main.rs:18:12
|
12 | pub fn get_mut(&mut self, key: &HeavyCloneKey) -> Option<&mut V> {
| - let's call the lifetime of this reference `'1`
13 | if let Some(v) = self.map.get_mut(key) {
| -------- mutable borrow occurs here
14 | return Some(v);
| ------- returning this value requires that `self.map` is borrowed for `'1`
...
18 | if self.map.len() > 64 {
| ^^^^^^^^ immutable borrow occurs here
These two borrows won't appear at the same time, what's the problem? How can I do this?
Although the code can be compiled by using contains_key before get_mut, it pays more overhead;
It helps a little to desugar the lifetimes by providing your own annotations on the references. It doesn't really matter here though as lifetimes aren't actually the issue.
pub fn get_mut<'s, 'k>(&'s mut self, key: &'k HeavyCloneKey) -> Option<&'s mut V> {
This gets us a little better error message:
error[E0502]: cannot borrow `self.map` as immutable because it is also borrowed as mutable
--> src/main.rs:18:12
|
12 | pub fn get_mut<'s, 'k>(&'s mut self, key: &'k HeavyCloneKey) -> Option<&'s mut V> {
| -- lifetime `'s` defined here
13 | if let Some(v) = self.map.get_mut(key) {
| -------- mutable borrow occurs here
14 | return Some(v);
| ------- returning this value requires that `self.map` is borrowed for `'s`
...
18 | if self.map.len() > 64 {
| ^^^^^^^^ immutable borrow occurs here
error[E0499]: cannot borrow `self.map` as mutable more than once at a time
--> src/main.rs:22:21
|
12 | pub fn get_mut<'s, 'k>(&'s mut self, key: &'k HeavyCloneKey) -> Option<&'s mut V> {
| -- lifetime `'s` defined here
13 | if let Some(v) = self.map.get_mut(key) {
| -------- first mutable borrow occurs here
14 | return Some(v);
| ------- returning this value requires that `self.map` is borrowed for `'s`
...
22 | let v = self.map.entry(key.clone()).or_insert_with(|| v);
| ^^^^^^^^ second mutable borrow occurs here
We have two errors here. Both stem from the rust compiler not being able to tell that we don't use the mutable borrow from line 13 later in the function.
The first says "you grabbed a mutable reference to self here so we can't let you have an immutable reference there". The second says "you grabbed a mutable reference to self here so we can't let you have a second mutable reference there".
How do we fix this? By making it clearer to the compiler that we'll never hold that first mutable reference. We can do this by manually checking if that key exists first. Change this
if let Some(v) = self.map.get_mut(key) {
return Some(v);
}
to this
if self.map.contains_key(key) {
return self.map.get_mut(key);
}
and it will compile.

Rust mutable borrow later used here [duplicate]

This question already has answers here:
Cannot borrow variable as mutable more than once at a time after calling a &'a mut self method
(2 answers)
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 3 years ago.
I have two structs, Parent and Child.
The Child references Parent's data, so I used a lifetime, but I got the error cannot borrow `p.childs` as immutable because it is also borrowed as mutable.
struct Parent<'a> {
data: String,
childs: Vec<Child<'a>>,
}
struct Child<'a> {
parent_data: &'a String,
}
impl<'a> Parent<'a> {
fn parse(&'a mut self) {
for _i in 0..10 {
let c = Child {
parent_data: &self.data,
};
self.childs.push(c);
}
}
}
fn main() {
let mut p = Parent {
data: "Hello".to_string(),
childs: Vec::new(),
};
p.parse();
for i in p.childs.iter() {
println!("{:?}", i.parent_data);
}
}
Errors:
error[E0502]: cannot borrow `p.childs` as immutable because it is also borrowed as mutable
--> src/main.rs:29:14
|
27 | p.parse();
| - mutable borrow occurs here
28 |
29 | for i in p.childs.iter() {
| ^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
How should I change the code?

Second mutable borrow error with only one mutable borrow [duplicate]

This question already has an answer here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 3 years ago.
This doesn't make much sense because it returns the same thing regardless of the if let, but it is a concise example of the problem that I am running into:
struct Data {
value: Option<i32>,
}
impl Data {
fn get(&mut self) -> Option<&mut i32> {
if let Some(val) = &mut self.value {
return Some(val);
}
return self.value.as_mut();
}
}
This code produces the error:
error[E0499]: cannot borrow `self.value` as mutable more than once at a time
--> src/lib.rs:11:16
|
6 | fn get(&mut self) -> Option<&mut i32> {
| - let's call the lifetime of this reference `'1`
7 | if let Some(val) = &mut self.value {
| --------------- first mutable borrow occurs here
8 | return Some(val);
| --------- returning this value requires that `self.value` is borrowed for `'1`
...
11 | return self.value.as_mut();
| ^^^^^^^^^^ second mutable borrow occurs here
I don't understand why this is a second mutable borrow when the first one goes out of scope before the second one will ever occur.
The val variable is not in scope after the if let, so how is this a second borrow? The first borrow should have already been released.
Just to be completely sure, I even surrounded the if let with another block:
{
if let Some(val) = &mut self.value {
return Some(val);
}
}
return self.value.as_mut();
This produced the same error. What is going on here?
The lifetime of 'a encompasses the entire function body because the return value needs to borrow self. Hence, the first borrow's scope extends past the if expression and into the entire function body.
Non Lexical Lifetimes were intended to fix this issue by reducing the scope of the first borrow to only include the if expression. You can see this in effect by moving the borrowed value into a local variable (playground):
fn get(&mut self) -> Option<&mut i32> {
let value = &mut self.value;
if let Some(val) = value {
return Some(val);
}
return value.as_mut();
}
However, the support for conditionally returning values was removed because it took too much compilation time. This feature is still being worked on and can be enabled with the -Zpolonius flag:
RUSTFLAGS="-Zpolonius" cargo +nightly build
With which, the original code compiles fine.

cannot borrow `self` as immutable because `self.chars` is also borrowed as mutable [duplicate]

This question already has answers here:
Mutably borrow one struct field while borrowing another in a closure
(2 answers)
Closed 5 years ago.
I need immutable access to one struct field and mutable access to another one, but they have to be stacked on each other. I've had this problem multiple times and I don't know how to fix this.
use std::collections::HashMap;
struct Bar;
impl Bar {
fn get(&self) -> i32 {
100
}
}
struct Foo {
chars: HashMap<char, i32>,
b: Bar,
}
impl Foo {
fn run(&mut self) {
self.chars.entry('c').or_insert_with(|| self.b.get() * 100);
}
}
fn main() {
let mut m = Foo {
chars: HashMap::new(),
b: Bar,
};
m.run();
}
error[E0502]: cannot borrow `self` as immutable because `self.chars` is also borrowed as mutable
--> src/main.rs:16:46
|
16 | self.chars.entry('c').or_insert_with(|| self.b.get() * 100);
| ---------- ^^ ---- - mutable borrow ends here
| | | |
| | | borrow occurs due to use of `self` in closure
| | immutable borrow occurs here
| mutable borrow occurs here
The problem is that you're trying to borrow self mutably and immutably, as the compiler says. As pointed out by Stefan, the borrow checker can't distinguish access to fields across closure boundaries, so we need to help it a bit by being more explicit about what we want to borrow and pass to the closure.
A way to do this is to take out a reference to self.b and use that inside the or_insert_with():
use std::collections::HashMap;
struct Bar;
impl Bar {
fn get(&self) -> i32 {
100
}
}
struct Foo {
chars: HashMap<char, i32>,
b: Bar,
}
impl Foo {
fn run(&mut self) {
let b = &self.b;
self.chars.entry('c').or_insert_with(|| b.get() * 100);
}
}
fn main() {
let mut m = Foo {
chars: HashMap::new(),
b: Bar,
};
m.run();
}

Resources