【发布时间】:2019-08-12 10:13:10
【问题描述】:
我正在 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 在第一种情况下不是可变借用的吗?
【问题讨论】:
-
你确定是借阅检查员弄糊涂了吗? ;)
-
我还没有遇到过一种语言,其中方法提取不能“正常工作”,但对 rust 来说是新手,不,我不确定。
-
mark_multiples可变地借用了整个self,但prime也是不可变地借用自 self。如果mark_multiples的实现决定替换self并删除原始版本,prime会发生什么?现在,你知道你的函数不会这样做,但编译器不会! -
Rust 引用就像读写锁一样工作。您要么以可变方式独占获取 (
&mut),要么以不可变方式获取共享锁 (&)。独占和共享不能同时发生。 -
@arlyon,方法提取在 Rust 中确实不是“正常工作”,因为借用检查器在每个函数中单独工作,只考虑其接口的签名。所以你可以提取函数,但是如果你传递给它们的引用比它们实际接触的更多,它们可能会在混合代码没有的地方开始冲突。这是非常有意的,因为它允许您重构函数体,确信您不会与某些调用者中的代码产生冲突。
标签: rust