The following code snippet compiles, but if you remove the comment around process1
, it fails to. The two functions process1
and process2
are intended to do the same job, but the simpler, process1
, is the one that doesn't compile, forcing a more verbose workaround in process2
.
use std::collections::HashMap;
pub struct Thing {
param: i64,
data: HashMap<String, i64>,
}
impl Thing {
fn expensive_derivation(&self, i: i64) -> i64 {
i * self.param
}
/*
fn process1(&mut self, s: &str) {
if let Some(v) = self.data.get_mut(s) {
let derived = self.expensive_derivation(*v);
*v = derived;
}
}
*/
fn process2(&mut self, s: &str) {
let mut pending: Option<i64> = None;
if let Some(v) = self.data.get(s) {
pending = Some(self.expensive_derivation(*v));
}
if let Some(p) = pending {
if let Some(v) = self.data.get_mut(s) {
*v = p;
}
}
}
}
The error is:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/lib.rs:15:27
|
14 | if let Some(v) = self.data.get_mut(s) {
| --------- mutable borrow occurs here
15 | let derived = self.expensive_derivation(*v);
| ^^^^ -- mutable borrow later used here
| |
| immutable borrow occurs here
error: aborting due to previous error
The question I have is, what bad thing is the Rust compiler trying to prevent with this compilation error? Since expensive_derivation
can't mutate self
, the call should not cause unexpected stuff to happen from process1
's point of view. I understand why mixing immutable and mutable references in the general case can lead to problems, but what could be the problem being prevented here?