0

When iterating a field from a structure, the for loop borrows the ownership on self if I understood correctly. This is annoying if one needs to call methods that mutate self.

This is distinct from How to run for loop on elements of a vector and change the vector inside the for loop and outside the for loop in rust? as I do not try to modify any element from the iterated set.

For instance, this code: (playground)

use std::collections::HashMap;

struct MyStruct {
    myset: HashMap<String,u8>,
    x: usize,
}

impl MyStruct {
    fn new(x: usize) -> MyStruct {
        MyStruct {
            myset: HashMap::new(),
            x: x, 
        }
    }
    
    fn fill(&mut self){
        self.myset.insert("John".to_string(), 12);
    }
    
    
    fn mutable_x_only(&mut self){
        self.x = 4;
    }
    
    fn try_iteration(&mut self){
        self.mutable_x_only(); // does work
        for (_name, _age) in &self.myset{ // this for loop borrows the `self`ownership
            self.mutable_x_only(); // does not work: self is not mutable here
        }
    }
}

fn main() {
    let mut my_struct_set = MyStruct::new(42);
    my_struct_set.fill();
    my_struct_set.try_iteration();
}

Generates this error:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:28:13
   |
27 |         for (_name, _age) in &self.myset{ // this for loop borrows the `self`ownership
   |                              -----------
   |                              |
   |                              immutable borrow occurs here
   |                              immutable borrow later used here
28 |             self.mutable_x_only(); // does not work: self is not mutable here
   |             ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

From my previous question, I understood that the ownership is taken by the for loop, but it appears that self itself is borrowed.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 1
    *that the ownership is taken by the for loop* — yes, ownership **of the reference** is taken: `&self.myset`. *if this function does not try to mutate `myset`* — **prove** that to the compiler. The signature of `mutable_function` allows for it to mutate `myset` (even if you currently are not). Change the signature such that it's statically impossible for that to be the case. – Shepmaster Aug 30 '21 at 14:18
  • 1
    @Shepmaster I have reformulated and simplified my question with respect to your feedbacks. Thanks ! – Pierre Peterlongo Aug 30 '21 at 14:48

0 Answers0