Multiple mutable borrow in a sequential code

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.

What type is session_map? Assuming HashMap, your code looks like the HashMap::retain method could be used.

2 Likes

But normally how do one repeatedly mutate an object inside a method?

I do this easily in other languages

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.

5 Likes

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.

1 Like

Thank You @steffahn i appreciate the effort.