修改原始值时更改借来的值

时间:2014-07-16 20:04:49

标签: pointers rust mutable

首先,这是我的代码的简化版本:

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
}

所以我喜欢创建可变对象并将它们添加到Manager中,但我应该能够修改原始对象,如代码中所示。

2 个答案:

答案 0 :(得分:2)

仅供参考,虽然接受的答案是完全正确的,但您可能会遇到许多情况,这种情况并不像简单的可变借用 - 从所有者那样方便从另一个位置访问对象

例如,如果你正在做某种观察者模式,其中一个位置正在使用一个对象,而另外一个地方正在观察对象的状态变化并在其发生变化时运行。

在这些情况下,您可能最好使用RefCell(http://doc.rust-lang.org/std/cell/struct.RefCell.html);你可以在多个地方拥有对象的引用,并且&#39; try_borrow()&#39;获取临时实例以查看特定的子范围。

在你的例子中,这可能有些过分,但是当你遇到更复杂的情况时,这就是拥有多个参考资料的一般解决方案&#39;对象。

答案 1 :(得分:1)

您的代码does not compile出现以下错误:

<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);

问题是,你不能修改一个借来的对象(这正是“借”字的语义,不是吗?)。当您使用obj1的可变引用并将其放入结构中时,您实际上阻止了对obj1的所有访问,直到此可变引用超出范围。但是因为当你试图重新分配obj1.size时还没有这样做,你就会收到这个错误。

This does work

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
}

此处manager出现在自己的范围内。因为该范围严格来自对obj1的访问,所以它可以正常工作。

如果您在借用这些数据时绝对必须访问这些数据,you have to go through the structure本身:

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
    }
}