Reputation: 197
Is it possible to borrow parts of a struct as mutable, and another part as immutable - if the struct's fields are private.
fn main() {
let mut ecs = EntityComponentSystem::new();
for e_id in ecs.get_entities_with_component::<Velocity>().unwrap() {
let components = ecs.get_mut_components(e_id);
...
}
impl EntityComponentSystem {
...
pub fn get_entities_with_component<K: Key>(&self) -> Option<&HashSet<u64>> {
self.entities_with_components.get(&TypeId::of::<K>())
}
pub fn get_mut_components(&mut self, entity_id: u64) -> &mut TypeMap {
let entity = self.entities.get_mut(&entity_id).unwrap();
&mut entity.components
}
}
pub struct EntityComponentSystem {
entities: HashMap<u64, Entity>, <------- I would like to modify this.
entities_with_components: HashMap<TypeId, HashSet<u64>>, <---- while reading from this!
}
The compiler is giving me:
error[E0502]: cannot borrow `*ecs` as mutable because it is also borrowed as immutable
--> physics.rs:19:26
|
18 | for e_id in ecs.get_entities_with_component::<Velocity>() {
| --- immutable borrow occurs here
19 | let components = ecs.get_mut_components(*e_id);
| ^^^ mutable borrow occurs here
...
26 | }
| - immutable borrow ends here
What I'm not grasping, is how the &self
reference in get_entities_with_component
is still borrowed after we've essentially returned a part of the entities_with_components
field.
Shouldn't just that part be borrowed? Is there any way to enforce this?
Upvotes: 11
Views: 7267
Reputation: 3752
You can only borrow the entire struct as immutable or mutable, there is no concept of borrowing only parts of it. When this becomes a problem, you can use interior mutability in the form of a RefCell
:
pub struct EntityComponentSystem {
entities: RefCell<HashMap<u64, Entity>>,
entities_with_components: HashMap<TypeId, HashSet<u64>>,
}
Now you can borrow the entire struct as immutable and borrow the contents of the RefCell
independently as mutable:
pub fn get_mut_components(&self, entity_id: u64) -> &mut TypeMap {
let mut entities = self.entities.borrow_mut();
let entity = entities.get_mut(&entity_id).unwrap();
&mut entity.components
}
Upvotes: 10
Reputation: 3861
No, a function cannot return a reference to a part of the structure and leave the structure partially borrowed.
However you can return tuple of immutable and mutable borrows like this
#[derive(Debug)]
struct AB(u32, u32);
impl AB {
fn borrow_parts(&mut self) -> (&u32, &mut u32) {
(&self.0, &mut self.1)
}
}
fn main() {
let mut ab = AB(0, 2);
{
let (a, b) = ab.borrow_parts();
*b = *a;
}
println!("{:?}", ab);
}
Upvotes: 2