Cannot borrow `*self` as mutable

I don't understand why this code doesn't work.
Please help.

Code:

 #[derive(Clone, Debug)]
 struct Element {
     name: String,
     foo: String,
 }
 
 struct Config {
     config_elements: Vec<Element>,
 }
 
 impl Config {
     fn new() -> Config
     {
         return Config{config_elements : Vec::new() };
     }
 }
 
 struct MyStruct {
     cfg : Config
 }
 
 impl MyStruct {
     fn new() -> MyStruct
     {
         let cs1_e1 = Element {
         name: "cs1_e1".to_string(),
         foo: "xxx".to_string(),
         };
         
         let cs1_e2 = Element {
         name: "cs1_e2".to_string(),
         foo: "yyy".to_string(),
         };
     
         let mut cfg = Config {
         config_elements: Vec::new(),
         };
     
         cfg.config_elements.push(cs1_e1);
         cfg.config_elements.push(cs1_e2);
     
         return MyStruct{cfg : cfg};
     }
     
     fn process(&mut self, e : &Element)
     {
 
     }
 
 }
 
 pub trait TestTrait {
     fn test(&mut self);
 }
 
 impl TestTrait for MyStruct {
     fn test(&mut self)
     {
         for e in &self.cfg.config_elements
 	    {
 	        self.process(e);
 	    }
     }
 }
 
 fn main() 
 {
     let c = MyStruct::new();
 }
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:61:10
   |
59 |         for e in &self.cfg.config_elements
   |                  -------------------------
   |                  |
   |                  immutable borrow occurs here
   |                  immutable borrow later used here
60 |         {
61 |             self.process(e);
   |             ^^^^^^^^^^^^^^^ mutable borrow occurs here

Rust Playground:
Click me

The rust compiler won't allow mutable and immutable borrows to overlap. You can overlap immutable borrows because this is read-only and completely safe.

1 Like

Ok. I think I understand now.

My fixed code : Click me

This code is unsafe according to Rust's aliasing rules. The borrow checker checks interfaces, not implementations, and the interface allows code like:

fn process(&mut self, e: &Element) {
    self.cfg.config_elements.clear();
    access(e); // boom! the element has been destroyed in the previous line
}

You can make all references shared/immutable, and potentially use interior mutability if needed.

You could split cfg out of self, so that self doesn't borrow it.

You could make process a "static" method without self and pass it only fields it needs.

2 Likes