Hello I am trying to borrow more than once in this code, how do i bypass it. i have checked other implementations, but it doesn't fit to my use case.
let arc_s_m :Arc<Mutex<SessionManager>>= self.session_manager.clone();
tokio::spawn(async move {
loop {
sleep(Duration::from_millis(1000)).await;
let mut sm = arc_s_m.lock().await;
let iter = sm.session_map.iter_mut();
for (k, v) in iter {
v.time_count = v.time_count - 1;
if v.time_count == 0 {
// second 'sm' borrow with issue
sm.session_map.remove_entry(k);
}
}
}
});
Please how do i get over this issue, i have read the docs, that says i should borrow in different scopes, but it didn't work.
The concrete issue you are seeing is called "iterator invalidation" and if you tried it in C# it would result in an InvalidOperationException and in C++ you may get undefined behaviour. The Rust compiler just prevents it at compile time.
This occurs when you have pointers/references into a collection (e.g. your iter variable) and do some sort of mutating operation which may cause those pointers/references to be invalidated (e.g. inserting or removing may cause a reallocation, leaving you with dangling pointers).
It sounds simple, but the way you deal with this is by not doing mutation when references are still alive.
There are generally two approaches, both of which you might have used in other languages.
You can iterate using indices/keys instead of an iterator. This limits how long you have pointers into the collection for so it no longer overlaps with the mutation.
Another approach which often works well when you are adding/removing a large number of items is to split it up into two passes - first you'll iterate over the collection to find which elements to remove, then you'll go through and remove them.
The problem is you want to iterate over a collection while trying to mutate it. This is a difficult and error-prone operation in any programming language. In Rust you typically circumvent this by using higher order functions like the HashMap::retain method @steffahn mentioned. Other examples would be functions like Iterator::map or Iterator::filter.