遍历结构中的Iterable时修改结构

时间:2019-08-12 10:13:10

标签: rust

我正在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在第一种情况下不是可变借来的吗?

1 个答案:

答案 0 :(得分:1)

为什么?因为self.primes是一成不变地借用的(因为Vec::iter,即新创建的迭代器,所以Iter引用的是self拥有的向量),而{{1 }}尝试借用mark_multiples作为可变变量。借用规则简单明了:

  1. 在给定的时间,您可以具有任意数量的对象的不可变借位,或者
  2. 您可以在给定时间一次借用一个对象。

因此,您不能拥有self的可变借项,而仍然拥有它的不可变借项,这正是编译器拒绝编译代码的原因。

为什么此安全功能在这里被认为有用?如果这意味着您要允许的意思,则可能会在self中进行迭代时,可以在方法self.primes中更改self.mark_multiples的值。您很容易碰到引用无效的内存位置!