I have a collection of objects owned by a struct Manager
. These objects have optional attributes such as printable
or dynamic
. I want to repeatedly loop over all printable objects to print them and loop over all dynamic objects to update them. My rather naive implementation is this:
struct Object {
state: i32,
printable: Option<i32>,
dynamic: Option<i32>
}
struct Manager {
objects: Vec<Object>,
}
impl Manager {
fn print_objects(&self) {
for o in &self.objects {
if let Some(i) = o.printable {
print!("{}: {}, ", i, o.state);
}
}
println!();
}
fn update_objects(&mut self) {
for o in &mut self.objects {
if let Some(i) = o.dynamic {
o.state += i;
}
}
}
}
fn main() {
let mut mgr = Manager{objects: Vec::new()};
mgr.objects.push(Object{state: 0, printable: Some(10), dynamic: None});
mgr.objects.push(Object{state: 0, printable: None, dynamic: Some(1)});
mgr.objects.push(Object{state: 0, printable: Some(20), dynamic: Some(2)});
for _ in 0..3 {
mgr.update_objects();
mgr.print_objects();
}
}
This solution has the drawback that it needs to loop over all objects and check each for the appropriate flag. Assuming that only a small fraction of the objects are dynamic, I'd rather avoid looping over all of them. In C++ I would simply create a list of pointers to the dynamic objects and loop over that. Attempting this:
struct Manager<'a> {
objects: Vec<Object>, // objects owned by Manager
dynamic: Vec<&'a Object> // references to dynamic objects
}
impl<'a> Manager<'a> { /* ... */ }
fn main() {
let mut mgr = Manager{objects: Vec::new(), dynamic: Vec::new()};
mgr.objects.push(Object{state: 0, printable: Some(10), dynamic: None});
mgr.objects.push(Object{state: 0, printable: None, dynamic: Some(1)});
mgr.objects.push(Object{state: 0, printable: Some(20), dynamic: Some(2)});
mgr.dynamic.push(&mgr.objects[1]);
mgr.dynamic.push(&mgr.objects[2]);
for _ in 0..3 {
mgr.update_objects(); // can't mutably borrow because of reference held by mgr.dynamic
mgr.print_objects();
}
}
It seems to be a very basic problem that I can't keep a reference to elements in Manager.objects
and at the same time borrow it mutably. Thus, I've started to doubt my whole approach. Is there an idiomatic way to implement such a pattern in Rust?
I believe that keeping references to objects prevents me from mutating them, but I'd be happy to learn a way around that. A future goal would be to change printable
or dynamic
during update, but I'd like to figure out the basic stuff before tackling that step.