Issue with HashMap and borrowing as mutable more than once at a time [duplicate] - hashmap

This question already has answers here:
Borrow two mutable values from the same HashMap
(2 answers)
How can I mutate other elements of a HashMap when using the entry pattern?
(2 answers)
How can I swap in a new value for a field in a mutable reference to a structure?
(2 answers)
How to use a struct's member as its own key when inserting the struct into a map without duplicating it?
(2 answers)
Closed 4 years ago.
I can't figure out a way to hold elements inside a HashMap and edit them at the same time:
use std::collections::HashMap;
#[derive(Clone, Debug)]
pub struct Alliance {
pub name: String,
pub id: u32,
}
fn main() {
let mut hashmap = HashMap::new();
let mut alliance1 = Alliance {
name: "alliance_1".to_string(),
id: 1,
};
let mut alliance2 = Alliance {
name: "alliance_2".to_string(),
id: 2,
};
// Do I really need to clone the name strings here?
let mut entry1 = hashmap.entry(alliance1.name.clone()).or_insert(alliance1);
let mut entry2 = hashmap.entry(alliance2.name.clone()).or_insert(alliance2);
swapNames(entry1, entry2);
println!("{}", entry1.name);
println!("{}", entry2.name);
}
fn swapNames(entry1: &mut Alliance, entry2: &mut Alliance) {
let aux = entry1.name.clone();
entry1.name = entry2.name.clone();
entry2.name = aux;
}
playground
I get an error which I agree with:
error[E0499]: cannot borrow `hashmap` as mutable more than once at a time
--> src/main.rs:24:22
|
23 | let mut entry1 = hashmap.entry(alliance1.name.clone()).or_insert(alliance1);
| ------- first mutable borrow occurs here
24 | let mut entry2 = hashmap.entry(alliance2.name.clone()).or_insert(alliance2);
| ^^^^^^^ second mutable borrow occurs here
...
30 | }
| - first borrow ends here
I just don't know how to code this in a way that compiles. I need to keep the Alliance structs mutable to further edit them down in the code (the swapNames function is just an example).

Related

How to store and retrieve objects in a container that mutate themselves & the container [duplicate]

This question already has answers here:
Borrow two mutable values from the same HashMap
(2 answers)
How can I mutate other elements of a HashMap when using the entry pattern?
(2 answers)
Mutable reference to container object within iterator loop
(1 answer)
Is there a way to add elements to a container while immutably borrowing earlier elements?
(1 answer)
Closed 4 years ago.
I have some objects that are constructed, stored in a single data structure, and updated during a run of my binary. Sometimes they get lonely and need friends, so they need to be able to search through the storage, locate a friend, remember the friend's identity, and tell the friend who they are.
struct Obj {
id: i32,
friend: Option<i32>,
}
impl Obj {
fn find_friend(&mut self, storage: &mut HashMap<i32, Obj>) {
// let's pretend we found this friend in storage
let friend_id = 1;
let new_friend = storage.get_mut(&friend_id).unwrap();
self.friend = Some(new_friend.id);
new_friend.friend = Some(self.id);
}
}
fn main() {
let mut storage: HashMap<i32, Obj> = HashMap::new();
let obj = Obj {
id: 0,
friend: None,
};
let id = obj.id;
storage.insert(id, obj);
// time passes
let obj_again = storage.get_mut(&id).unwrap();
obj_again.find_friend(&mut storage);
}
Unfortunately I get in fights with the borrow checker:
error[E0499]: cannot borrow `storage` as mutable more than once at a time
--> src\main.rs:190:22
|
189 | let obj_again = storage.get_mut(&id).unwrap();
| ------- first mutable borrow occurs here
190 | obj_again.find_friend(&mut storage);
| ^^^^^^^ second mutable borrow occurs here
191 | }
| - first borrow ends here
error: aborting due to previous error
How can I structure this code such that I can fetch a reference to an object out of storage and then allow it to mutate itself, its compatriots, and the data structure that contains them?
Edit: I'm not sure that this is a duplicate of the question "How do I get two mutable references into a container?" This is "How can an object inside a container mutate itself if it also needs to be able to mutate its container?". Sorry if that wasn't clear.

Cannot borrow `self.objects` as mutable more than once at a time [duplicate]

I am trying to add multiple elements to a HashMap in a for loop but can't seem to get it right:
use std::collections::HashMap;
fn set_if_needed_and_get(hmap: &mut HashMap<String, String>, st: String) -> &String {
hmap.entry(st.clone()).or_insert(st.clone())
}
fn main() {
let meeting_one_email = ["email1", "email2", "email1"];
let mut hmap: HashMap<String, String> = HashMap::new();
let mut attendees: std::vec::Vec<&String> = std::vec::Vec::new();
for m in meeting_one_email.iter() {
attendees.push(set_if_needed_and_get(&mut hmap, m.to_string()));
}
}
I get the error:
error[E0499]: cannot borrow `hmap` as mutable more than once at a time
--> src/main.rs:14:51
|
14 | attendees.push(set_if_needed_and_get(&mut hmap, m.to_string()));
| ^^^^ mutable borrow starts here in previous iteration of loop
15 | }
16 | }
| - mutable borrow ends here
I understand that I cannot borrow hmap as mutable more than once, so how can I solve this while still using a for loop? Using a set and inserting in batches would work, but I want to use a for loop.
Your problem is not that you are trying to add elements to your HashMap in a loop, it's that you are modifying your hashmap and trying access your hmap in the scope of the loop.
As you have a mutable borrow on hmap, you are not allowed to push its elements to your attendees vector in the loop. Adding a value to the HashMap may require that the hashmap reallocate itself, which would invalidate any references to values inside it.
One easy solution for your problem could be this:
fn main() {
let meeting_one_email = ["email1", "email2", "email1"];
let mut hmap: HashMap<String, String> = HashMap::new();
for m in meeting_one_email.iter() {
set_if_needed_and_get(&mut hmap, m.to_string());
}
let attendees: Vec<&String> = hmap.keys().collect();
}
In this code, you are accessing the hashmap after filling it up to also fill your attendees vector.

Adding entries to a HashMap and getting references to them in a for loop

I am trying to add multiple elements to a HashMap in a for loop but can't seem to get it right:
use std::collections::HashMap;
fn set_if_needed_and_get(hmap: &mut HashMap<String, String>, st: String) -> &String {
hmap.entry(st.clone()).or_insert(st.clone())
}
fn main() {
let meeting_one_email = ["email1", "email2", "email1"];
let mut hmap: HashMap<String, String> = HashMap::new();
let mut attendees: std::vec::Vec<&String> = std::vec::Vec::new();
for m in meeting_one_email.iter() {
attendees.push(set_if_needed_and_get(&mut hmap, m.to_string()));
}
}
I get the error:
error[E0499]: cannot borrow `hmap` as mutable more than once at a time
--> src/main.rs:14:51
|
14 | attendees.push(set_if_needed_and_get(&mut hmap, m.to_string()));
| ^^^^ mutable borrow starts here in previous iteration of loop
15 | }
16 | }
| - mutable borrow ends here
I understand that I cannot borrow hmap as mutable more than once, so how can I solve this while still using a for loop? Using a set and inserting in batches would work, but I want to use a for loop.
Your problem is not that you are trying to add elements to your HashMap in a loop, it's that you are modifying your hashmap and trying access your hmap in the scope of the loop.
As you have a mutable borrow on hmap, you are not allowed to push its elements to your attendees vector in the loop. Adding a value to the HashMap may require that the hashmap reallocate itself, which would invalidate any references to values inside it.
One easy solution for your problem could be this:
fn main() {
let meeting_one_email = ["email1", "email2", "email1"];
let mut hmap: HashMap<String, String> = HashMap::new();
for m in meeting_one_email.iter() {
set_if_needed_and_get(&mut hmap, m.to_string());
}
let attendees: Vec<&String> = hmap.keys().collect();
}
In this code, you are accessing the hashmap after filling it up to also fill your attendees vector.

Check a mutable object and then alter it using a member of the object [duplicate]

This question already has answers here:
Cannot borrow `*x` as mutable because it is also borrowed as immutable
(2 answers)
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 5 years ago.
I want to do something similar to this code:
use std::collections::HashMap;
fn main() {
let mut vars = HashMap::<String, String>::new();
find_and_do_someth(&mut vars);
}
fn find_and_do_someth(map: &mut HashMap<String, String>) {
match map.get("test") {
None => { /* Do nothing */ }
Some(string) => do_someth(map, string),
}
}
fn do_someth(map: &mut HashMap<String, String>, val: &str) {
// Do something that alters map
}
I get the following compiler error:
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
--> src/main.rs:11:35
|
9 | match map.get("test") {
| --- immutable borrow occurs here
10 | None => { /* Do nothing */ }
11 | Some(string) => do_someth(map, string),
| ^^^ mutable borrow occurs here
12 | }
| - immutable borrow ends here
Is there a general Rust-friendly work-around for this use case?
Check something on an object
If condition is verified, alter the object
The above is just a simple example using a HashMap.
Case by case, I seem to always find a convoluted solution, however I am not used yet to the way of thinking necessary to master Rust.

How do I extract two mutable elements from a Vec in rust [duplicate]

This question already has answers here:
How to get mutable references to two array elements at the same time?
(8 answers)
Closed 6 years ago.
I'm trying to extract two elements from a Vec, which will always contain at least two elements. These two elements need to be extracted mutably as I need to be able to change values on both as part of a single operation.
Sample code:
struct Piece {
x: u32,
y: u32,
name: &'static str
}
impl Piece {
fn exec(&self, target: &mut Piece) {
println!("{} -> {}", self.name, target.name)
}
}
struct Board {
pieces: Vec<Piece>
}
fn main() {
let mut board = Board {
pieces: vec![
Piece{ x: 0, y: 0, name: "A" },
Piece{ x: 1, y: 1, name: "B" }
]
};
let mut a = board.pieces.get_mut(0);
let mut b = board.pieces.get_mut(1);
a.exec(b);
}
At present, this fails to build with the following compiler errors:
piece.rs:26:17: 26:29 error: cannot borrow `board.pieces` as mutable more than once at a time
piece.rs:26 let mut b = board.pieces.get_mut(1);
^~~~~~~~~~~~
piece.rs:25:17: 25:29 note: previous borrow of `board.pieces` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `board.pieces` until the borrow ends
piece.rs:25 let mut a = board.pieces.get_mut(0);
^~~~~~~~~~~~
piece.rs:28:2: 28:2 note: previous borrow ends here
piece.rs:17 fn main() {
...
piece.rs:28 }
Unfortunately, I need to be able to obtain a mutable reference to both so that I can modify both within the Piece.exec method. Any ideas, or am I trying to do this the wrong way?
Rust can't guarantee at compile time that get_mut is not going to mutably borrow the same element twice, so get_mut borrows the entire vector mutably.
Instead, use slices
pieces.as_slice().split_at_mut(1) is what you want to use here.

Resources