Reputation: 800
First of all, here is a simplified version of my code I'm working on:
struct Object {
size: f32
}
impl Object {
fn on_event(&mut self) {
self.size += 1.0;
println!("Object notified. New size: {}.", self.size);
}
}
struct Manager<'a> {
objects: Vec<&'a mut Object>
}
impl<'a> Manager<'a> {
fn add(&mut self, obj: &'a mut Object) {
self.objects.push(obj);
}
fn notify_objects(&mut self) {
for i in range(0u, self.objects.len()) {
let ref mut obj = *self.objects.get_mut(i);
obj.on_event();
}
}
}
fn main() {
let mut obj1 = Object { size: 1.0 };
let mut obj2 = Object { size: 2.0 };
let mut obj3 = Object { size: 3.0 };
let mut manager = Manager { objects: Vec::new() };
manager.add(&mut obj1);
manager.add(&mut obj2);
manager.add(&mut obj3);
obj1.size = 25.0;
println!("before {}", obj1.size); // should print 25
manager.notify_objects();
println!("after {}", obj1.size); should print 26
}
So I like to create mutable Objects and add them to the Manager, but I should be able to modify the original Objects like shown in the code.
Upvotes: 2
Views: 2046
Reputation: 35216
Just FYI, although the accepted answer is totally correct, you'll probably encounter many situations where it's not as convenient as simple mutable-borrow-back-from-owner to access an object from another location.
For example, if you're doing some kind of observer pattern where one location is using an object, and somewhere separate is watching the object for state changes and running something if it changes.
In those situations you're probably best off using RefCell (http://doc.rust-lang.org/std/cell/struct.RefCell.html); you can own references to an object in multiple places, and 'try_borrow()' to get a temporary instance to look at in a specific sub scope.
In your example that's perhaps overkill, but as you hit more complex situations, that's the general solution for having 'multiple references' to an object.
Upvotes: 2
Reputation: 128141
Your code does not compile with errors like this:
<anon>:38:5: 38:21 error: cannot assign to `obj1.size` because it is borrowed
<anon>:38 obj1.size = 25.0;
^~~~~~~~~~~~~~~~
<anon>:34:22: 34:26 note: borrow of `obj1.size` occurs here
<anon>:34 manager.add(&mut obj1);
The problem is, you can't modify an object which has been borrowed (that's exactly the semantics of "borrow" word, isn't it?). When you take a mutable reference of obj1
and put it into the structure, you're effectively blocking all access to obj1
until this mutable reference goes out of scope. But because it haven't done that yet when you're trying to reassign obj1.size
, you're getting this error.
fn main() {
let mut obj1 = Object { size: 25.0 };
let mut obj2 = Object { size: 2.0 };
let mut obj3 = Object { size: 3.0 };
obj1.size = 25.0;
println!("before {}", obj1.size); // should print 25
{
let mut manager = Manager { objects: Vec::new() };
manager.add(&mut obj1);
manager.add(&mut obj2);
manager.add(&mut obj3);
manager.notify_objects();
}
println!("after {}", obj1.size); // should print 26
}
Here manager
appears in its own scope. Because that scope is strictly between accesses to obj1
, it works fine.
If you absolutely must access these data while it is borrowed, you have to go through the structure itself:
fn main() {
let mut obj1 = Object { size: 1.0 };
let mut obj2 = Object { size: 2.0 };
let mut obj3 = Object { size: 3.0 };
let mut manager = Manager { objects: Vec::new() };
manager.add(&mut obj1);
manager.add(&mut obj2);
manager.add(&mut obj3);
{
let obj1 = manager.objects.get_mut(0); // returns mutable reference
obj1.size = 25.0;
println!("before {}", obj1.size); // should print 25
}
manager.notify_objects();
{
let obj1 = manager.objects.get(0); // returns immutable reference
println!("after {}", obj1.size); // should print 26
}
}
Upvotes: 1