Is there any fundamental reason that the following isn’t possible?
let mut map = HashMap::new();
...
let elt1 = map.get_mut("key 1").expect("getting elt 1");
let elt2 = map.get_mut("key 2").expect("getting elt 2");
elt1.do_something();
elt2.do_something_too();
elt1.do_something_else();
Obviously the current borrow checker won’t allow the line let elt2 = ...
because there is already a mutable reference to map
, and map
does not have a get_mut_two(k1, k2)
operation. But elt1
and elt2
do not overlap and get_mut
does not move elements so will not invalidate pointers to existing elements. Tricky, but is is this actually possible to implement?
A simpler example:
struct A {
data: Vec<T>,
name: Option<String>,
};
impl A {
fn set_name(&mut self, name: String) {
if self.name.is_some() { panic!("Help! My name is not supposed to change!"); }
self.name = Some(name);
}
fn read_data(&mut self) {
for item in self.data { // reference to self.data over the following block
if let Some(name) = item.get_name() {
self.set_name(name); // requires a mutable reference to self, except it doesn't...
} else ....
}
}
}
In this example, in-lining the set_name
method or passing it a mutable reference directly to self.name
would solve the problem. But why is this necessary? Well, because we don’t have any way of annotating set_name
to say that it only mutates self.name
and does not even read other members of self
. Which, if available, would make the set_name
function signature more complex, but might still be useful if set_name
is used a lot.
To be clear, none of this functionality is required for anything I’ve wanted to do, it would just be nice.
So, is this possible? The second example should be quite straight-forward since the fields in question are fixed at compile-time. The first example is similar but I can’t currently see a way of doing it without run-time checks, but I’m not convinced this should be necessary (except to ensure "key 1" != "key 2"
).