简体   繁体   English

Rayon 出错,不能借用 `*self` 作为可变的,因为它是 `Fn` 闭包中的捕获变量

[英]Error with Rayon, cannot borrow `*self` as mutable, as it is a captured variable in a `Fn` closure

First of all, I'm new toRust.首先,我是 Rust 的新手。 For a game I'm working on I need to call function to change pixels on a vector that is then transformed into an iamge.对于我正在开发的游戏,我需要调用 function 来更改矢量上的像素,然后将其转换为图像。 For that, I have a struct that contains all the context of the game, include said image and everything I need to calcaulate the pixels.为此,我有一个包含游戏所有上下文的结构,包括所述图像和计算像素所需的一切。

This works with a single thread but not when I try to parallelize it with Rayon.这适用于单个线程,但当我尝试将其与 Rayon 并行化时则无效。

Here's a simplified code as an example of the problem.这是一个简化的代码作为问题的示例。 It works with chunks_mut .它适用于chunks_mut

use ::rayon::prelude::*;
struct Game {
    pub pixel: [u8; 4],
    pub pixel_vec: Vec<u8>,
}

impl Game {
    pub fn new(pixel: [u8; 4], length: usize) -> Self {
        let pixel_vec = vec![2; length];

        Self { pixel, pixel_vec }
    }
    pub fn draw(&mut self) {
        let mut pixel_vec = std::mem::take(&mut self.pixel_vec);

        pixel_vec
            .par_chunks_mut(4)
            .for_each(|slice| self.some_function(slice));
        self.pixel_vec = pixel_vec;
    }

    fn some_function(&mut self, slice: &mut [u8]) {
        for i in 0..slice.len() {
            slice[i] = self.pixel[i] * self.pixel[i];
        }
    }
}

fn main() {
    let mut game = Game::new([0, 3, 0, 0], 20);
    game.draw();
}

Error错误

Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow `*self` as mutable, as it is a captured variable in a `Fn` closure
  --> src/main.rs:18:31
   |
18 |             .for_each(|slice| self.some_function(slice));
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

For more information about this error, try `rustc --explain E0596`.
error: could not compile `playground` due to previous error

Your Game::some_function function uses the &mut self receiver. Your Game::some_function function 使用&mut self接收器。 This means that it must borrow self mutably.这意味着它必须可变地借用self That is, self.some_function(slice) is the same as Game::some_function(&mut self, slice) .也就是说, self.some_function(slice)Game::some_function(&mut self, slice)相同。

So when you call self.some_function(slice) in your closure, the closure must capture self as mutable, since it needs to borrow self as mutable to call the function. However, the for_each function requires a Fn closure and a Fn closure will not let you capture as mutable (for good reason).因此,当您在闭包中调用self.some_function(slice)时,闭包必须将self捕获为可变的,因为它需要借用self作为可变的来调用 function。但是, for_each function 需要Fn闭包,而Fn闭包不会让您捕获为可变的(有充分的理由)。

The solution in your case is to change the receiver in some_function to &self , since as written that function doesn't need mutable access to self :您的解决方案是将some_function中的接收器更改为&self ,因为正如所写的那样 function 不需要对self进行可变访问:

fn some_function(&self, slice: &mut [u8]) {
    // ...
}

Edit:编辑:

To complete the explanation: the rayon par_chunks_mut method returns a type that implements ParallelIterator , which is where the for_each method comes from.完成解释:人造丝par_chunks_mut方法返回一个实现ParallelIterator的类型,这是for_each方法的来源。 That's where the argument implementing Fn is required.这就是需要参数实现Fn的地方。

Now thinking about the available closure traits in Rust, why Fn ?现在想想 Rust 中可用的闭包特征,为什么是Fn Well the other options are FnOnce or FnMut .那么其他选项是FnOnceFnMut FnOnce consumes the closure when called once and thus can only be called at most once (hence the name), clearly this isn't going to work for a for_each method. FnOnce在调用一次时消耗闭包,因此最多只能调用一次(因此得名),显然这不适用于for_each方法。 FnMut is weaker, it can capture variables mutably, so why does rayon not use that? FnMut较弱,它可以可变地捕获变量,那么为什么 rayon 不用它呢? The entire point is to call this closure concurrently in different threads, which you can't do if you're mutating its state, you'd have to synchronise the mutable access which would effectively serialise the operation, making the whole thing a waste of time.重点是在不同的线程中同时调用这个闭包,如果你改变它的 state,你就不能这样做,你必须同步可变访问,这将有效地序列化操作,使整个事情成为浪费时间。 Thus, Fn is the only option and no mutable captures are allowed.因此, Fn是唯一的选择,不允许进行可变捕获。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 不能将&#39;Fn`闭包中捕获的外部变量借用为可变 - Cannot borrow captured outer variable in an `Fn` closure as mutable 当使用带有Rc的闭包时,无法在Fn闭包中借用捕获的外部变量 - Cannot borrow captured outer variable in an Fn closure when using a closure with an Rc 用par_iter()替换iter():不能在`Fn`闭包中捕获的外部变量中可变地借用数据 - Replace iter() with par_iter(): cannot borrow data mutably in a captured outer variable in an `Fn` closure 无法移出“Fn”闭包中捕获的变量 - Cannot move out a captured variable in an `Fn` closure 无法移出`Fn`闭包中的捕获变量 - Cannot move out of captured variable in an `Fn` closure 为什么将值移到闭包中仍然会出现错误消息“无法借用不可变的局部变量作为可变变量”? - Why does moving a value into a closure still have the error message “cannot borrow immutable local variable as mutable”? 无法移出 `guess`,在 `Fn` 闭包 Rust 中捕获的变量 - cannot move out of `guess`, a captured variable in an `Fn` closure Rust 无法移出“Fn”闭包中捕获的外部变量 - Cannot move out of captured outer variable in an `Fn` closure 无法移出Fn闭包中捕获的外部变量 - Cannot move out of captured outer variable in an Fn closure 不能将 X 作为不可变借用,因为它在可变闭包中也作为可变借用 - Cannot borrow X as immutable because it is also borrowed as mutable in a mutable closure
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM