簡體   English   中英

修改原始值時更改借來的值

[英]Change borrowed value when modifying original value

首先,這是我正在處理的代碼的簡化版本:

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中,但我應該能夠修改原始對象,如代碼中所示。

僅供參考,雖然接受的答案是完全正確的,但您可能會遇到許多情況,它不像簡單的可變借用 - 從 - 所有者那樣方便從另一個位置訪問對象。

例如,如果你正在做某種觀察者模式,其中一個位置正在使用一個對象,而另一個單獨的位置正在觀察對象的狀態變化並在其發生變化時運行。

在這些情況下,您可能最好使用RefCell( http://doc.rust-lang.org/std/cell/struct.RefCell.html ); 您可以在多個位置擁有對象的引用,並使用'try_borrow()'來獲取在特定子范圍中查看的臨時實例。

在你的例子中,這可能是過度的,但是當你遇到更復雜的情況時,這就是對一個對象進行“多次引用”的一般解決方案。

您的代碼無法編譯 ,如下所示:

<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時它還沒有這樣做,你得到了這個錯誤。

這確實有效

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之間,所以它工作正常。

如果您在借用這些數據時絕對必須訪問這些數據,則必須完成結構本身:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM