我正在Rust中实施滚动式主筛。结构看起来像这样:
struct Sieve {
window_index: u32,
window_size: u32,
board: BitVec,
primes: Vec<u32>,
}
有一个移动的“窗口”,其中素数倍数在大小为window_size
的板上标记,并且遇到的任何未标记的数字都称为素数。
移动窗口时,需要重新初始化新板,并标记所有先前发现的素数的所有倍数。
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)
}
}
确切的逻辑并不重要,但是您可以看到存在self.primes
不变的借用和self.board
可变的借用。编译器很高兴。将逻辑提取到函数中时出现问题:
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
为什么借阅检查器在这里变得困惑? self
在第一种情况下不是可变借来的吗?
答案 0 :(得分:1)
为什么?因为self.primes
是一成不变地借用的(因为Vec::iter
,即新创建的迭代器,所以Iter
引用的是self
拥有的向量),而{{1 }}尝试借用mark_multiples
作为可变变量。借用规则简单明了:
因此,您不能拥有self
的可变借项,而仍然拥有它的不可变借项,这正是编译器拒绝编译代码的原因。
为什么此安全功能在这里被认为有用?如果这意味着您要允许的意思,则可能会在self
中进行迭代时,可以在方法self.primes
中更改self.mark_multiples
的值。您很容易碰到引用无效的内存位置!