0

I'm trying to do a nested loop that mutates objects, breaks out of the loop at some point, and keeps track of the last values encountered. The following contrived example gives the idea.

The problem I'm having is the borrow checker won't let me loop over the collection and also return a value out of it. I managed to work around it by tracking the indices of the last values, but that seems hackish and wouldn't work if I just had iterators instead of Vectors. I also tried using nested try_fold() loops, which ran into the same issue.

Main question: How can we make this work without resorting to indices?

Bonus question: Is the code as written actually safe? ie, is the code broken, or is the code fine and the borrow checker just not smart enough to realize that?

use rand::Rng;

fn main() {
    let randos = std::iter::from_fn(|| Some(rand::thread_rng().gen_range(0..10)));
    let mut accumulators = vec![Accumulator { count: 0 }, Accumulator { count: 0 }];
    let mut winning_accumulator = None;
    let mut last_num = None;

    for num in randos {
        //Next line compiles with error
        //error[E0499]: cannot borrow `accumulators` as mutable more than once at a time
        //`accumulators` was mutably borrowed here in the previous iteration of the loop
        for acc in &mut accumulators {
            if acc.add(num) > 100 {
                winning_accumulator = Some(acc);
                last_num = Some(num);
                break;
            }
        }
    }

    println!(
        "Last num: {}, total: {}",
        last_num.unwrap(),
        winning_accumulator.unwrap().count
    );
}

struct Accumulator {
    count: u64,
}

impl Accumulator {
    fn add(&mut self, val: u64) -> u64 {
        //pretend we're doing something complicated here
        self.count += val;
        self.count
    }
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
Brian Reischl
  • 7,216
  • 2
  • 35
  • 46
  • 1
    + break should be write this way https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=afa8c6fe1f7bba7f89e7f6a8b2730e22 – Stargateur Dec 13 '21 at 19:00
  • @Stargateur I saw that question but I'm still learning Rust, so I'm not sure how I'd apply the solution to this situation. So perhaps it does answer the question but I just don't understand it. And thanks for the info on `break`, I had not run into that feature yet! – Brian Reischl Dec 13 '21 at 19:20
  • 1
    answer is too complicated to be explain it's not even my level after years of rust, TL;DR, you ask too much to the current borrow checker do simpler code. the "apply the solution to this situation" is in the playground link I give you it's compile with `RUSTFLAGS="-Z polonius" cargo +nightly check` more specific answer but just the same problem https://stackoverflow.com/a/50570026/7076153 – Stargateur Dec 13 '21 at 20:18

0 Answers0