Rust mutable borrow later used here [duplicate] - rust

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?

Related

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.

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

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.

How to use the ref values of a HashMap without having the compiler complaining about borrowing the map [duplicate]

This question already has answers here:
How can I mutate other elements of a HashMap when using the entry pattern?
(2 answers)
Borrow two mutable values from the same HashMap
(2 answers)
Closed 4 years ago.
How do I use an HashMap as a cache correctly? Accessing the value needs to borrow the HashMap (as mutable in my case) which restricts my ability to access more than one value, and restrict the usage of one value at the same time (and the cache itself).
Hypothetical example below:
use std::collections::HashMap;
struct Cache {
storage: HashMap<i32, String>,
}
impl Cache {
fn new() -> Self {
Cache {
storage: HashMap::new(),
}
}
fn get_or_compute(&mut self, x: i32) -> &mut String {
self.storage.entry(x).or_insert(x.to_string())
}
}
fn do_something(cache: &mut Cache, s: &String) {
println!("Cache value:{}, s:{}", cache.get_or_compute(23), s)
}
fn main() {
let mut cache = Cache::new();
let a = cache.get_or_compute(1);
let _b = cache.get_or_compute(2);
do_something(&mut cache, a)
}
Rust Playground
The compiler (rightfully) complains with:
error[E0499]: cannot borrow `cache` as mutable more than once at a time
--> src/main.rs:30:14
|
29 | let a = cache.get_or_compute(1);
| ----- first mutable borrow occurs here
30 | let _b = cache.get_or_compute(2);
| ^^^^^ second mutable borrow occurs here
31 |
32 | do_something(&mut cache, a)
| - first borrow later used here
error[E0499]: cannot borrow `cache` as mutable more than once at a time
--> src/main.rs:32:18
|
29 | let a = cache.get_or_compute(1);
| ----- first mutable borrow occurs here
...
32 | do_something(&mut cache, a)
| ^^^^^^^^^^ - first borrow later used here
| |
| second mutable borrow occurs here
I suppose it has to do with some missing lifetime annotation, but I'm too noob to see how to fix the issue.

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

Cannot borrow immutable borrowed content as mutable

I'm trying to develop a message routing app. I've read the official Rust docs and some articles and thought that I got how pointers, owning, and borrowing stuff works but realized that I didn't.
use std::collections::HashMap;
use std::vec::Vec;
struct Component {
address: &'static str,
available_workers: i32,
lang: i32
}
struct Components {
data: HashMap<i32, Vec<Component>>
}
impl Components {
fn new() -> Components {
Components {data: HashMap::new() }
}
fn addOrUpdate(&mut self, component: Component) -> &Components {
if !self.data.contains_key(&component.lang) {
self.data.insert(component.lang, vec![component]);
} else {
let mut q = self.data.get(&component.lang); // this extra line is required because of the error: borrowed value does not live long enough
let mut queue = q.as_mut().unwrap();
queue.remove(0);
queue.push(component);
}
self
}
}
(Also available on the playground)
Produces the error:
error: cannot borrow immutable borrowed content `**queue` as mutable
--> src/main.rs:26:13
|
26 | queue.remove(0);
| ^^^^^ cannot borrow as mutable
error: cannot borrow immutable borrowed content `**queue` as mutable
--> src/main.rs:27:13
|
27 | queue.push(component);
| ^^^^^ cannot borrow as mutable
Could you please explain the error and it would be great if you can give me the right implementation.
Here is an MCVE of your problem:
use std::collections::HashMap;
struct Components {
data: HashMap<u8, Vec<u8>>,
}
impl Components {
fn add_or_update(&mut self, component: u8) {
let mut q = self.data.get(&component);
let mut queue = q.as_mut().unwrap();
queue.remove(0);
}
}
Before NLL
error[E0596]: cannot borrow immutable borrowed content `**queue` as mutable
--> src/lib.rs:11:9
|
11 | queue.remove(0);
| ^^^^^ cannot borrow as mutable
After NLL
error[E0596]: cannot borrow `**queue` as mutable, as it is behind a `&` reference
--> src/lib.rs:11:9
|
11 | queue.remove(0);
| ^^^^^ cannot borrow as mutable
Many times, when something seems surprising like this, it's useful to print out the types involved. Let's print out the type of queue:
let mut queue: () = q.as_mut().unwrap();
error[E0308]: mismatched types
--> src/lib.rs:10:29
|
10 | let mut queue: () = q.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^ expected (), found mutable reference
|
= note: expected type `()`
found type `&mut &std::vec::Vec<u8>`
We have a mutable reference to an immutable reference to a Vec<u8>. Because we have an immutable reference to the Vec, we cannot modify it! Changing self.data.get to self.data.get_mut changes the type to &mut &mut collections::vec::Vec<u8> and the code compiles.
If you want to implement the concept of "insert or update", you should check into the entry API, which is more efficient and concise.
Beyond that, Rust uses snake_case for method naming, not camelCase.

Resources