Search code examples
rustborrowingmutability

How to call a method while iterating in Rust


Appologies if this is very simple. I'm learning rust and getting used to the strange borrowing system. Usually, you can get the desired behavior just by changing the syntax of your method calls, however, in this case, there seems to be now way.

A simplified version of my code is this: EventPump if from SDL.

struct Example {
    pump: EventPump
}

impl Example {
    fn method(&mut self) {
        for event in pump.poll_iter() {
            self.other_method();
        }
    }

    fn other_method(&self) {

    }
}

However, I am getting the following error:

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src\game.rs:53:67
   |
30 |             for event in self.pump.poll_iter();
   |                          ---------------------
   |                          | 
   |                          mutable borrow occurs here
   |                          mutable borrow later used here
...
53 |                  self.other_method();
   |                  ^^^^ immutable borrow occurs here

There is probably some proper way to do this so my struct can maintain ownership of itself, but I have not been able to find it.

I have tried the following:

  • Turn it into a while loop with explicit while let event = iterator.next(), same error
  • Making the function mutable, the error now says that no two mutable references are allowed either. I guess the entire "immutability" part of the error message is actually irrelevant.

I could perhaps copy the entire contents of the iterable into a vector or such, but that would defeat the purpose of a iterator, and what if the iterator is not finite? There has to be a better way right...

If someone with more rust experience could help me out it would be much appreciated.


Solution

  • If you want an attribute of a struct to be mutable when there is an immutable reference of a struct in the same block, you'll need RefCell. This is called interior mutability.

    If an interior mutability of struct Example is desired, then you will need a RefCell.

    use sdl2::{EventPump};
    
    struct Example {
        pump: RefCell<EventPump> // wrap in RefCell
    }
    
    impl Example {
        // you have to decide whether you want a mutable or immutable chained methods
        // i.e. method and other_method should be of same mutability because
        // other method is called in method
        fn method(&self) {
            // borrow a mutable reference of pump inside a method with immutable self 
            let mut pump = self.pump.borrow_mut();
            for event in pump.poll_iter() {
                self.other_method();
            }
        }
    
        fn other_method(&self) {
    
        }
    }