问题描述
我希望将 iter()
替换为 Rayon's par_iter()
在这样一个相当简单的情况下,但我没有这样做.
之前的代码:
indexes_to_increment.iter().for_each(|x| self.some_data[*x as usize] += 1);`
这是人造丝修改后的代码:
extern crate rayon;使用人造丝::前奏::*;fn 主(){让 mut a = SomeStruct::new(vec![1, 0, 0, 1]);a.add_factor_indexes(&vec![1, 2]);println!("{:?}", a);//吐出SomeStruct { some_data: [1, 1, 1, 1] }"}#[派生(调试)]struct SomeStruct {some_data: Vec<u8>,}impl SomeStruct {fn new(some_data: Vec) ->一些结构{SomeStruct { some_data }}fn add_factor_indexes(&mut self, index_to_increment: &[u8]) {//indexes_to_increment.iter().for_each(|x| self.some_data[*x as usize] += 1);索引到增量.par_iter().for_each(|x| self.some_data[*x as usize] += 1);}}
(游乐场)
虽然我知道以下错误消息告诉我该怎么做,但此时我无法这样做.
错误[E0387]:不能在`Fn`闭包中捕获的外部变量中可变地借用数据-->src/main.rs:23:27|23 |.for_each(|x| self.some_data[*x as usize] += 1);|^^^^^^^^^^^^^^^|help: 考虑改变这个闭包以通过可变引用获取 self-->src/main.rs:23:23|23 |.for_each(|x| self.some_data[*x as usize] += 1);|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果我知道 add_factor_indexes
中的 indexes_to_increment
向量只包含唯一的 u8
并且可以用集合替换,那会改变什么吗?
此错误消息是正是 Rust 旨在为您提供的错误预防类型的一个示例.换句话说,编译器阻止您同时可变地访问同一块内存.
从概念上讲,您尝试运行的代码应该是安全的,因为您总是访问完全不相交的向量部分,不会有任何重叠的相同索引的可变借用,但编译器无法分辨.它所看到的只是 self.some_data
被多次可变地借用;它不知道 Index
的实现做了什么或者闭包的主体做了什么.
您可以在向量中找到所有匹配的槽,然后迭代所有结果:
fn add_factor_indexes(&mut self,index_to_increment: &[u8]) {self.some_data.par_iter_mut().枚举().filter(|&(i, _)| index_to_increment.contains(&(i as u8))).map(|(_, v)| v).for_each(|x| *x += 1);}
并且可以用一组替换
由于重复查找,如果数据量较大,我会推荐它.
I was hoping to replace an iter()
with Rayon's par_iter()
in a rather simple case like this, but I am failing to do so.
The previous code:
indexes_to_increment
.iter()
.for_each(|x| self.some_data[*x as usize] += 1);`
Here's the Rayon-modified code:
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);
}
}
While I know that the following error message is telling me what to do, at this point I'm unable to do so.
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);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If I knew that the indexes_to_increment
vector in add_factor_indexes
only contains unique u8
s and could be replaced with a set, would that change anything?
This error message is an example of exactly the type of error prevention that Rust is designed to provide to you. Said another way, the compiler is preventing you from mutably accessing the same piece of memory concurrently.
Conceptually, the code you are trying to run should be safe because you are always accessing a completely disjoint piece of the vector, there won't be any overlapping mutable borrows of the same index, but the compiler cannot tell that. All it sees is that self.some_data
is borrowed mutably multiple times; it doesn't know what the implementation of Index
does or what the body of the closure does.
You could find all the matching slots in the vector and then iterate over all of the results:
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);
}
I'd recommend it due to the repeated lookups, if it's a larger amount of data.
这篇关于用 par_iter() 替换 iter():不能在 Fn 闭包中捕获的外部变量中可变地借用数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!