Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - Cannot borrow immutable borrowed content as mutable

I'm trying to develop a message routing app. I've read the official Rust docs and some articles and thought that I got how pointers, owning, and borrowing stuff works but realized that I didn't.

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
    }

}

(Also available on the playground)

Produces the error:

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

Could you please explain the error and it would be great if you can give me the right implementation.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is an MCVE of your problem:

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

Before NLL

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

After 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

Many times, when something seems surprising like this, it's useful to print out the types involved. Let's print out the type of 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>`

We have a mutable reference to an immutable reference to a Vec<u8>. Because we have an immutable reference to the Vec, we cannot modify it! Changing self.data.get to self.data.get_mut changes the type to &mut &mut collections::vec::Vec<u8> and the code compiles.


If you want to implement the concept of "insert or update", you should check into the entry API, which is more efficient and concise.

Beyond that, Rust uses snake_case for method naming, not camelCase.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...