I have a following example that works fine.
use std::collections::HashMap;
#[derive(Debug)]
struct MyStruct {
map: HashMap<usize, usize>,
counter: usize,
}
fn process_counter(instance: &mut MyStruct) {
for &key in instance.map.keys() {
let value = instance.map[&key];
instance.counter += value;
}
}
fn main() {
let mut instance = MyStruct {
map: HashMap::from([(0, 5), (1, 10)]),
counter: 0,
};
process_counter(&mut instance); // MyStruct { map: {0: 5, 1: 10}, counter: 15 }
println!("{:?}", instance);
}
But if I want to take the body of the for-loop away into a separate function I get such error:
cannot borrow `*instance` as mutable because it is also borrowed as immutable
Here is the code:
use std::collections::HashMap;
#[derive(Debug)]
struct MyStruct {
map: HashMap<usize, usize>,
counter: usize,
}
// This function added
fn increment_counter(instance: &mut MyStruct, key: usize) {
let value = instance.map[&key];
instance.counter += value;
}
fn process_counter(instance: &mut MyStruct) {
for &key in instance.map.keys() {
increment_counter(instance, key); // The body moved to increment_counter
}
}
fn main() {
let mut instance = MyStruct {
map: HashMap::from([(0, 5), (1, 10)]),
counter: 0,
};
process_counter(&mut instance);
println!("{:?}", instance);
}
The reason of the error is quite clear: the compiler does let me modify instance
fully, because I already iterate the keys (that belong to instance
) immutably in the loop, so I am not allowed to pass instance
as mutable into an external function. But in my real project the code of increment_counter
is quite long and complited and it is called multiple times in different places so I would like to keep it in a separate function.
What is the best way to separate the logic of increment_counter
inside of process_counter
?
Maybe I could iterate keys in a different way or consider different arguments for increment_counter
?
I also tried to iterate keys using a vector this way, but I do not like this solution because it is consuming for the performance and memory.
let keys: Vec<usize> = instance.map.keys().cloned().collect();