Mutably borrow a hash map inside a loop [duplicate] - rust

This question already has answers here:
Why does this mutable borrow live beyond its scope?
(2 answers)
Closed 8 months ago.
I'd like to mutably borrow a hash map on every iteration of a loop.
I have the following hash map, function, and loop:
use std::collections::HashMap;
fn func<'a>(hash_map: &'a mut HashMap<&'a str, String>) {
unimplimented!();
}
fn loop() {
let mut hash_map = HashMap::new();
let mut i = 0;
while i < 10 {
func(&mut hash_map);
i += 1;
}
}
This will produce the following error on the func(&mut hash_map); line:
cannot borrow `hash_map` as mutable more than once at a time
`hash_map` was mutably borrowed here in the previous iteration of the looprustc(E0499)
main.rs(62, 25): `hash_map` was mutably borrowed here in the previous iteration of the loop
How can I refactor this to be able to mutably borrow the hash map on every iteration of the loop?
I believe I understand Rust's ownership rules enough to understand why this error is happening, just not well enough to fix it.
Note: I know there are better ways to write a loop in Rust, just wanted a very simple loop for this example.

Looks like I was using an unneeded lifetime in the function argument type definition. Instead of hash_map: &'a mut HashMap<&'a str, String>, I could just use hash_map: &mut HashMap<&'a str, String>.
The following code works for me.
use std::collections::HashMap;
use external::func;
fn func<'a>(hash_map: &mut HashMap<&'a str, String>) {
unimplimented!();
}
fn loop() {
let mut hash_map = HashMap::new();
let mut i = 0;
while i < 10 {
func(&mut hash_map);
i += 1;
}
}

Related

Does a mutable String reference implement Copy [duplicate]

This question already has answers here:
Why is the mutable reference not moved here?
(4 answers)
Do mutable references have move semantics?
(1 answer)
Closed 1 year ago.
In the below code I was expecting the compiler to complain about use of moved value: xref on hello function's second call since mutable references do not implement Copy. The compiler doesn't raise any such error. What am I missing here?
fn main() {
let mut x: String = "Developer".to_string();
let x_ref: &mut String = &mut x;
hello(x_ref);
hello(x_ref);
}
fn hello(a: &mut String) {
println!("Hello {}", a);
}
Your example uses the mutable references after each other, which allows the compiler to perform an implicit reborrow. It basically turns this code into this:
hello(&mut *x_ref);
hello(&mut *x_ref);
Now you have two separate mutable borrows each only for the lifetime of the function call, thus they do not conflict with each other.
You see an error if you try to use it two times simultaneously.
fn main() {
let mut x: String = "Developer".to_string();
let x_ref: &mut String = &mut x;
hello(x_ref, x_ref);
}
fn hello(a: &mut String, b: &mut String) {
println!("Hello {} and {}", a, b);
}

rust: expected lifetime parameter problem [duplicate]

This question already has answers here:
How to return new data from a function as a reference without borrow checker issues?
(1 answer)
Return local String as a slice (&str)
(7 answers)
Closed 3 years ago.
I am new to Rust and was making a simple program to practice which takes 2 numbers and prints the numbers between them. This is my code
fn main() {
let a: u32 = 2;
let b: u32 = 10;
let a = result(&a, &b);
println!("{:?}", a);
}
fn result(a: &u32, b: &u32) -> [Vec<&u32>] {
let mut vec = Vec::new();
for x in a..b {
vec.push(a);
}
vec
}
When i run this program, i get this error
fn result(a: &u32, b: &u32) -> [Vec<&u32>] {
| ^ expected lifetime parameter
The concepts of borrowing and lifetimes are still very new and strange to me. Please help me in determining where i am wrong.
The error message is quite clear here:
this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from a or b
Providing an explicit lifetime would help the compiler understand what you're trying to do:
fn result<'a>(a: &'a u32, b: &'a u32) -> Vec<&'a u32> {
let mut vec: Vec<&'a u32> = Vec::new();
for x in *a..*b {
vec.push(&x);
}
vec
}
But the above wouldn't work either, as borrowing x results in borrowing a variable whch only lives in the scope a single iteration:
vec.push(&x);
^^ borrowed value does not live long enough
What you probably want is to avoid borrowing altogether:
fn result(a: u32, b: u32) -> Vec<u32> {
let mut vec = Vec::new();
for x in a..b {
vec.push(x);
}
vec
}
live example on godbolt.org

Mutable borrow in loop [duplicate]

This question already has answers here:
Linking the lifetimes of self and a reference in method
(1 answer)
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
(2 answers)
Closed 5 years ago.
I am trying to get a mutable borrow inside a loop, and I cannot get it to work. I've tried all the possible guards, raw pointers, everything.
struct Test<'a> {
a: &'a str,
}
impl<'a> Test<'a> {
pub fn new() -> Self {
Test { a: &mut "test" }
}
pub fn dostuff(&'a mut self) {
self.a = "test";
}
pub fn fixme(&'a mut self) {
let mut i = 0;
while i < 10 {
self.dostuff();
i += 1;
}
}
}
fn main() {
let mut test = Test::new();
test.fixme();
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:19:13
|
19 | self.dostuff();
| ^^^^ mutable borrow starts here in previous iteration of loop
...
22 | }
| - mutable borrow ends here
Rust Playground example code
I cannot manage to figure how to solve this. I need the fix to still keep the function signatures the same. My code is a lot more complex, but this snippet strips it down to the bare minimum.
Here is the complete code of what I'm trying to solve.
When you write fn dostuff(&'a mut self) you are enforcing that the reference to self must live at least as long as the lifetime 'a. But it's the same 'a as you have used in the definition of the Test struct. This means that callers of dostuff have to lend self for the entire lifetime of test. After dostuff() has been called once, self is now borrowed and the borrow doesn't finish until test is dropped. By definition, you can only call that function once, so you cannot call it in a loop.
I need the fix to still keep the function signatures the same
So, you should now understand that this is an impossible requirement. You can have either the function signature as it is, or you can call it in a loop. You can't have both.

How to pass a HashMap to a function in Rust [duplicate]

This question already has answers here:
What's the difference between placing "mut" before a variable name and after the ":"?
(4 answers)
Closed 6 years ago.
Can anybody explain why following code does not compile?
use std::collections::HashMap;
fn add(mut h: &HashMap<&str, &str>) {
h.insert("foo", "bar");
}
fn main() {
let mut h: HashMap<&str, &str> = HashMap::new();
add(&h);
println!("{:?}", h.get("foo"));
}
This is what rustc tells me
hashtest.rs:4:5: 4:6 error: cannot borrow immutable borrowed content `*h` as mutable
hashtest.rs:4 h.insert("foo", "bar");
^
The problem is that you pass a mutable reference to a HashMap (i.e. the reference can be changed to point to another HashMap), and not a reference to a mutable HashMap (i.e. the HashMap can change).
Here is a correct code:
use std::collections::HashMap;
fn add(h: &mut HashMap<&str, &str>) {
h.insert("foo", "bar");
}
fn main() {
let mut h: HashMap<&str, &str> = HashMap::new();
add(&mut h);
println!("{:?}", h.get("foo"));
}

Why does HashMap::get_mut() take ownership of the map for the rest of the scope?

I have the following code that inserts some values into a HashMap and then gets them back out:
use std::collections::HashMap;
fn things() {
let mut map = HashMap::new();
map.insert(5, "thing");
map.insert(4, "world");
map.insert(1, "hello");
let mut thing = map.remove(&5);
let mut world = map.get_mut(&4);
let mut hello = map.get_mut(&1);
}
Attempting to compile this code gives the following error:
error[E0499]: cannot borrow `map` as mutable more than once at a time
--> src/main.rs:10:21
|
9 | let mut world = map.get_mut(&4);
| --- first mutable borrow occurs here
10 | let mut hello = map.get_mut(&1);
| ^^^ second mutable borrow occurs here
11 | }
| - first borrow ends here
After perusing the API docs for both the remove() and get_mut() methods (fortunately they are pretty close to each other!) there is nothing that stands out to me from the method signatures why the remove() method does not mutably borrow the map for the rest of the current scope while the get_mut() method does.
The other piece of data that I have that also mystifies me is that this code compiles:
use std::collections::HashMap;
fn things() {
let mut map = HashMap::new();
map.insert(5, "thing");
map.insert(4, "world");
map.insert(1, "hello");
let mut thing = map.remove(&5);
map.get_mut(&4);
let mut hello = map.get_mut(&1);
}
Not storing the result of the first call to get_mut() doesn't cause the map to be mutably borrowed for the rest of the scope? How could I have known this from looking at the documentation? Am I missing something else?
This error is a limitation of the implementation of the borrow checker before non-lexical lifetimes. With those enabled, the original code will work as-is:
use std::collections::HashMap;
fn things() {
let mut map = HashMap::new();
map.insert(5, "thing");
map.insert(4, "world");
map.insert(1, "hello");
let mut thing = map.remove(&5);
let mut world = map.get_mut(&4);
let mut hello = map.get_mut(&1);
}
fn main() {}
This is because the compiler is smarter and can see that you aren't using world anymore by the time you get to map.get_mut(&1), so it doesn't need to have a valid reference anymore.
You can get equivalent code in previous versions of Rust by adding an explicit scope:
let mut thing = map.remove(&5);
{
let mut world = map.get_mut(&4);
}
let mut hello = map.get_mut(&1);
Why does HashMap::get_mut() take ownership of the map
It absolutely does not do that. Ownership is a precise term in Rust code. Note that the error message specifically says
previous borrow of map occurs here
A borrow is not ownership. If I borrow your car, I don't own your car.
Your real question is "why does it borrow it for the rest of the scope". Let's look at the signature:
fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: Hash + Eq,
In words, this could be read as
Given a mutable reference to a HashMap (&mut self) and something that can be used to find the key (K: Borrow<Q>, Q: Hash + Eq), return a mutable reference to the value if one matches (Option<&mut V>)
However, that returned mutable reference will be changing something in the HashMap, that's why it's a mutable reference at all. You are only allowed to have multiple immutable borrows OR one mutable borrow at a time. This prevents writing code that causes inconsistencies and safety issues.
Let's look at remove:
fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq,
This returns an owned value, not a reference into the HashMap. Once the method is done, the borrow of the map is over.

Resources