4

I want to get a returning value from a method inside a loop. But iterator is also borrowed as a mutable. And the method want an immutable reference.

This is a small reproducible code (playground link):

struct Foo {
    numbers: Vec<u8>,
    constant: u8
}

impl Foo {
    pub fn new()-> Foo {
        Foo {
            numbers: vec!(1,2,3,4),
            constant: 1
        }
    }

    pub fn get_mut(&mut self){
        for mut nmb in self.numbers.iter_mut() {
            {
                let constant = self.get_const();
            }
        }
    }

    pub fn get_const(&self)-> u8 {
        self.constant
    }
}

fn main() {
    let mut foo = Foo::new();

    foo.get_mut();
}

I am getting an error like below:

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/main.rs:17:32
   |
15 |         for  nmb in self.numbers.iter_mut() {
   |                     -----------------------
   |                     |
   |                     mutable borrow occurs here
   |                     mutable borrow later used here
16 |             {
17 |                 let constant = self.get_const();
   |                                ^^^^ immutable borrow occurs here
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 2
    Is this just an example, or would doing `let constant = self.constant;` be okay in your case? – loganfsmyth Jun 04 '20 at 20:36
  • @loganfsmyth This is a small example. I want to calculate some data based on the `numbers` vector. – Ramesh Kithsiri HettiArachchi Jun 04 '20 at 20:39
  • 2
    If the value returned by `get_const` remains constant throughout the execution of the loop, you can also store it in a variable outside the loop. – EvilTak Jun 04 '20 at 20:47
  • 1
    @EvilTak returning value of get_const is based on the current state on `numbers` vector. I have used `u8` for only the example. This should be a struct when it in my use case. – Ramesh Kithsiri HettiArachchi Jun 04 '20 at 20:53
  • Possibly relevant: https://stackoverflow.com/questions/30073684/how-to-get-mutable-references-to-two-array-elements-at-the-same-time – Mateen Ulhaq Jun 04 '20 at 22:07
  • Do you need the _entire_ `numbers` dataset, or some portion of it? That would affect whether that is relevant. Is your loop actually mutating `numbers` by the way? If so, do you only need the `numbers` that are _before_ the one you're currently processing? – loganfsmyth Jun 04 '20 at 22:32
  • 2
    You may have to index into `numbers` instead of using an iterator. That way you can narrow the lifetime of the mutable borrow to the part of the code where you really mutate the value ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c582be6a46e4572b6481a43df207b71c)). – Jmb Jun 05 '20 at 06:45

1 Answers1

2

If self.get_const() is independent of self.numbers, you can either calculate it outside the loop:

let constant = self.get_const();
for mut nmb in self.numbers.iter_mut() {
    // ...
}

or access the field directly:

for mut nmb in self.numbers.iter_mut() {
    let constant = self.constant;
}

If it depends on self.numbers, you need to use indexing. Make sure to calculate the constant before indexing:

for i in 0..self.numbers.len() {
    let constant = self.get_const();
    let nmb = &mut self.numbers[i];
}

You also need to make sure not to insert or remove any values, since that is likely to cause bugs with the indexing.

Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45