CurrentVals::perform_task takes a mutable reference to self and mutates Self (in unspecified manner but with the guarantee that CurrentVals::vals will NOT be mutated).
#![allow(unused)]
struct Val {
// ...
}
struct CurrentVals {
vals: Vec<Val>,
// ...
}
impl CurrentVals {
fn perform_task(&mut self, val: &Val) {
// ...
}
pub fn new() -> Self {
// vals is filled in an unspecified manner
Self { vals: vec![] }
}
}
pub fn main() {
let mut current_vals = CurrentVals::new();
for val in ¤t_vals.vals {
current_vals.perform_task(val)
}
}
When I try to execute the program, Rust shows the error:
| for val in ¤t_vals.vals {
| ------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
| current_vals.perform_task(val)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
While I know why this error happens, I would like to know how I can solve the issue.
Well, then don't take the entirety of &mut self. Mutably borrow only those parts/fields which actually need to be mutated. If you move the splitting into the same function, the borrow checker can reason about it just fine:
pub fn main() {
let mut current_vals = CurrentVals::new();
for val in ¤t_vals.vals {
CurrentVals::perform_task(&mut current_vals.other_thing, val);
}
}
The issue is, it is yet unknown how many parts/fields will actually be mutated. It can be 5, 10, 20 etc. I cannot possibly update the function all the time, more so given the fact that it will be a part of the public API.
Thanks for the solution. It'll work, but it makes me feel uneasy about Rust's inner mechanics. To the (biased) human eye, it looks like it is a simple task that should not take too much of thinking, but Rust's guarantee of protection backfires here.
Anyways, this solution works just fine! Thanks a lot!
I am not a pro in Rust. And since I come from C/Python background, I had no idea I'd trip over a simple programming problem. But since I'm still learning, what looks difficult/arcane right now will become the norm.
It's not us you need to convince, it's the compiler. There is absolutely nothing wrong, as far as the compiler knows, with some future maintainer coming along one day and changing the body of perform_task to do exactly that. The easiest way to tell the compiler that a function doesn't mutate something, is not to pass that thing to the function at all.