Error[E0502]: cannot borrow as mutable because it is also borrowed as immutable


Why I write this code correct?

struct Module {
    name: String,
    messages: Vec<String>,

impl Module {
    fn new(name: String) -> Module {
        Module {
            name: name,
            messages: Vec::new(),

    fn print(&mut self) {
        match self.messages.get(0) {
            Some(msg) => {}
            None => {
                self.messages.push("empty list".to_string());
        let messages = self.messages.join("\n");
        println!("Module {}\n{}",, messages);

fn main() {
    let mut module = Module::new("Main".to_string());
error[E0502]: cannot borrow `self.messages` as mutable because it is also borrowed as immutable
  --> src/
18 |         match self.messages.get(0) {
   |               ------------- immutable borrow occurs here
21 |                 self.messages.push("empty list".to_string());
   |                 ^^^^^^^^^^^^^ mutable borrow occurs here
22 |             }
23 |         }
   |         - immutable borrow ends here

error: aborting due to previous error


The borrow checker is not all that sophisticated. The process to make it smarter is called nonlexical borrows.

It decided that you wanted to borrow self.messages for the entire match statement, because you used self.messages.get. It is complaining as you are also mutably borrowing it within that statement with self.messages.push.


Borrows are based on types and static scopes. The return type of self.messages.get(0) is an Option<&String>, which is a type that may contain a reference. Even in the None branch of the match, the borrow checker still believes that the return value may have a reference in it that would be invalidated by the push.

To get around that, you can restructure your code to break the dependency. Something like

let is_empty = match self.messages.get(0) {
    Some(_) => false,
    None => true
if is_empty {
    self.messages.push("empty list".to_string());

Or use a method that doesn’t potentially return a reference:

if self.messages.is_empty() {
    self.messages.push("empty list".to_string());