无法将不可变借用的内容作为可变的借用。

23

我正在尝试开发一款消息路由应用程序。我已经阅读了官方的Rust文档和一些文章,认为我已经理解了指针、所有权和借用的工作原理,但后来发现我并没有。

use std::collections::HashMap;
use std::vec::Vec;

struct Component {
    address: &'static str,
    available_workers: i32,
    lang: i32
}

struct Components {
    data: HashMap<i32, Vec<Component>>
}

impl Components {
    fn new() -> Components {
        Components {data: HashMap::new() }
    }

    fn addOrUpdate(&mut self, component: Component) -> &Components {
        if !self.data.contains_key(&component.lang) {

            self.data.insert(component.lang, vec![component]);
        } else {
            let mut q = self.data.get(&component.lang); // this extra line is required because of the error: borrowed value does not live long enough
            let mut queue = q.as_mut().unwrap();
            queue.remove(0);
            queue.push(component);
        }
        self
    }

}

(也可在playground上使用)

产生错误:

error: cannot borrow immutable borrowed content `**queue` as mutable
  --> src/main.rs:26:13
   |
26 |             queue.remove(0);
   |             ^^^^^ cannot borrow as mutable

error: cannot borrow immutable borrowed content `**queue` as mutable
  --> src/main.rs:27:13
   |
27 |             queue.push(component);
   |             ^^^^^ cannot borrow as mutable

你能否解释一下错误,并提供正确的实现将会很棒。

1个回答

37

这里是你的问题的MCVE

use std::collections::HashMap;

struct Components {
    data: HashMap<u8, Vec<u8>>,
}

impl Components {
    fn add_or_update(&mut self, component: u8) {
        let mut q = self.data.get(&component);
        let mut queue = q.as_mut().unwrap();
        queue.remove(0);
    }
}

在NLL之前

error[E0596]: cannot borrow immutable borrowed content `**queue` as mutable
  --> src/lib.rs:11:9
   |
11 |         queue.remove(0);
   |         ^^^^^ cannot borrow as mutable

经过NLL

error[E0596]: cannot borrow `**queue` as mutable, as it is behind a `&` reference
  --> src/lib.rs:11:9
   |
11 |         queue.remove(0);
   |         ^^^^^ cannot borrow as mutable

很多时候,当像这样的事情似乎令人惊讶时,打印出涉及的类型是有用的:打印出队列(queue)的类型。让我们打印一下 queue 的类型:

let mut queue: () = q.as_mut().unwrap();
error[E0308]: mismatched types
  --> src/lib.rs:10:29
   |
10 |         let mut queue: () = q.as_mut().unwrap();
   |                             ^^^^^^^^^^^^^^^^^^^ expected (), found mutable reference
   |
   = note: expected type `()`
              found type `&mut &std::vec::Vec<u8>`

我们有一个对不可变引用的可变引用,指向一个Vec<u8>。因为我们持有Vec的不可变引用,所以无法修改它!将self.data.get更改为self.data.get_mut会改变类型为&mut &mut collections::vec::Vec<u8>,代码就可以编译。


如果您想实现“插入或更新”这个概念,应该使用entryAPI,这样更高效简洁。

此外,Rust使用snake_case来命名方法,而不是camelCase


谢谢。现在我更明白了。感谢您关于打印类型的建议,它对故障排除非常有帮助。 - dmgcodevil
print out the types involved”下的链接还存在吗?有一个SO的问题,但我认为链接指向了某个答案。 - stej
1
@stej 这个链接是问题的链接。这样可以让更好的答案进来,或者如果情况不同,实现者可以选择不同的答案。在这种情况下,我使用了“分配给空元组”的版本。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接