I am trying to figure out a strategy/language mechanism that allows for reading one field in a struct and, while in scope of the read, write to another field. It seems should be able to inform Rust this is safe (assuming I'm right that it is) but I can't figure out how.
It seems I would have to completely extract the value/reference from the struct and then separately write it back, which would seems messy in other situations than just manipulating a string.
The code below doesn't compile complaining of too much borrowing.
The compiler only knows how to do this if both of the internal references are generated in the same function. One approach is to accept a closure to allow arbitrary user code to be run in a specific context:
For some reason, this reminds me of pin projection (not entirely related, but the idea we can alter the wrapper of individual fields in structs applies here to the degree that we need a split Ref and RefMut). Maybe, this calls for implementing a borrow-projection macro to make it easier for beginners, thus removing the need to do everything in a single function?
It’s also possible to define an explicit borrow splitting method, and use newtypes to control what the downstream user can do with the split references.
pub struct MapRef<'a> ( & 'a mut HashMap<String,String>);
impl<'a> MapRef<'a> {
/* methods that are independent of `s` */
}
pub struct StrRef<'a>( &'a mut String );
impl<'a> StrRef<'a> {
/* methods that are independent of `map` */
}
pub struct ContainerRefs<'a> {
pub map: MapRef<'a>,
pub s: StrRef<'a>,
}
impl Container {
pub fn split_mut(&mut self)->ContainerRefs<'_> {
ContainerRefs {
map: MapRef(&mut self.map),
s: StrRef(&mut self.s)
}
}
/* methods that require both `map` and `s` */
}
Not exactly; the problem you were having was that main needed an &mut Container (to update s) at the same time as an &Container (to get the key). Both versions of update_s_from_key get around this by accessing Container’s fields directly instead of through functions, which lets the compiler treat them as independent variables.
Thank you both for the insights. Each of these examples is correct, instructive and helpful. I'm awarding the solution to the one that is closest to what I implemented, but all could work.