用par_iter()替换iter():不能在`Fn`闭包中捕获的外部变量中可变地借用数据

man*_*mat 3 rust rayon

我希望在一个相当简单的情况下iter()Rayon 替换一个par_iter(),但我没有这样做.

上一个代码:

indexes_to_increment
    .iter()
    .for_each(|x| self.some_data[*x as usize] += 1);`
Run Code Online (Sandbox Code Playgroud)

这是人造丝修改过的代码:

extern crate rayon;
use rayon::prelude::*;

fn main() {
    let mut a = SomeStruct::new(vec![1, 0, 0, 1]);
    a.add_factor_indexes(&vec![1, 2]);
    println!("{:?}", a); // spits out "SomeStruct { some_data: [1, 1, 1, 1] }"
}

#[derive(Debug)]
struct SomeStruct {
    some_data: Vec<u8>,
}

impl SomeStruct {
    fn new(some_data: Vec<u8>) -> SomeStruct {
        SomeStruct { some_data }
    }
    fn add_factor_indexes(&mut self, indexes_to_increment: &[u8]) {
        //indexes_to_increment.iter().for_each(|x| self.some_data[*x as usize] += 1);
        indexes_to_increment
            .par_iter()
            .for_each(|x| self.some_data[*x as usize] += 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

虽然我知道以下错误消息告诉我该怎么做,但此时我无法这样做.

error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure
  --> src/main.rs:23:27
   |
23 |             .for_each(|x| self.some_data[*x as usize] += 1);
   |                           ^^^^^^^^^^^^^^
   |
help: consider changing this closure to take self by mutable reference
  --> src/main.rs:23:23
   |
23 |             .for_each(|x| self.some_data[*x as usize] += 1);
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

如果我知道indexes_to_increment向量中add_factor_indexes只包含唯一的u8s并且可以用集合替换,那会改变什么吗?

She*_*ter 6

此错误消息的一个例子正是生锈的目的是提供给您防错的类型.换句话说,编译器阻止您同时可变地访问同一块内存.

从概念上讲,你试图运行的代码应该是安全的,因为你总是访问一个完全不相交的向量,没有任何重叠的可变借用相同的索引,但编译器无法分辨.它所看到的只是self.some_data多次可以借用; 它不知道实现的Index实现或封闭体的作用.

可以在向量中找到所有匹配的插槽,然后迭代所有结果:

fn add_factor_indexes(&mut self, indexes_to_increment: &[u8]) {
    self.some_data
        .par_iter_mut()
        .enumerate()
        .filter(|&(i, _)| indexes_to_increment.contains(&(i as u8)))
        .map(|(_, v)| v)
        .for_each(|x| *x += 1);
}
Run Code Online (Sandbox Code Playgroud)

并且可以用一套替换

如果它是大量的数据,我会推荐它,因为重复查找.