I am implementing a rolling prime sieve in Rust. The struct looks like this:
struct Sieve {
window_index: u32,
window_size: u32,
board: BitVec,
primes: Vec<u32>,
}
There is a moving 'window' in which prime multiples are marked on a board of size window_size
, and any numbers encountered that are unmarked are known to be prime.
When the window is moved, the new board needs to be re-initialized with all the multiples of the previously discovered primes marked.
let square_optimization = (self.window_index + self.window_size).integer_sqrt();
for &prime in self.primes.iter().filter(|&&p| p < square_optimization) {
let remainder = self.window_index % prime;
let start_prime = if remainder > 0 { self.window_index + prime - remainder } else { remainder };
if start_prime > self.window_index + self.window_size { return; }
for i in (start_prime % self.window_size..self.window_size).step_by(prime as usize) {
self.board.set(i as usize, true)
}
}
The exact logic doesn't matter, however you can see that there is an immutable borrow of self.primes
and a mutable borrow of self.board
. The compiler is happy. The problem appears when extracting the logic into a function:
fn mark_multiples(&mut self, prime: u32) {
let remainder = self.window_index % prime;
let start_prime = if remainder > 0 { self.window_index + prime - remainder } else { remainder };
if start_prime > self.window_index + self.window_size { return; }
for i in (start_prime % self.window_size..self.window_size).step_by(prime as usize) {
self.board.set(i as usize, true)
}
}
fn compute_chunk(&mut self) {
let square_optimization = (self.window_index + self.window_size).integer_sqrt();
for &prime in self.primes.iter().filter(|&&p| p < square_optimization) {
self.mark_multiples(prime)
}
// do work
}
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/lib.rs:54:13
|
53 | for &prime in self.primes.iter().filter(|&&p| p < square_optimization) {
| --------------------------------------------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
54 | self.mark_multiples(prime)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Why does the borrow checker get confused here? Is self
not mutably borrowed in the first case?