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 Vector
s. 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
}
}