在循环中借用可变变量

Borrow mutable in a loop

我尝试处理具有多个工作线程的数组,就像 Rayon 的 par_iter() 函数一样,但我想要一个可变引用 target,每个线程一个。

我有一个像这样的简单函数


pub fn parallel_map_vector<A:Sync,T:Send,B:Send>(a:&[A], t:&mut [T], b:&mut [B], f:impl Fn(&A,&mut T)+Send+Sync){
    assert_eq!(a.len(),b.len());
    let atomic_counter = AtomicUsize::new(0);
    crossbeam::scope(|scope| {
        for target in t {
            scope.spawn( |_| {
                loop {
                    let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
                    if idx < a.len() {unsafe{std::slice::from_raw_parts_mut(b,b_len)};
                        f(&a[idx], target)
                    }else{
                        break
                    }
                }
            });
        }
    }).unwrap();
}

出于某种原因,我一直收到错误消息

error[E0373]: closure may outlive the current function, but it borrows `target`, which is owned by the current function
  --> htm/src/parallel.rs:11:26
   |
9  |     crossbeam::scope(|scope| {
   |                       ----- has type `&crossbeam::thread::Scope<'1>`
10 |         for target in t {
11 |             scope.spawn( |_| {
   |                          ^^^ may outlive borrowed value `target`
...
17 |                         f(&a[idx], target)
   |                                    ------ `target` is borrowed here
   |
note: function requires argument type to outlive `'1`
  --> htm/src/parallel.rs:11:13
   |
11 | /             scope.spawn( |_| {
12 | |                 loop {
13 | |                     let idx = atomic_counter.fetch_add(1, Ordering::Relaxed);
14 | |                     if idx < a.len() {
...  |
21 | |                 }
22 | |             });
   | |______________^
help: to force the closure to take ownership of `target` (and any other referenced variables), use the `move` keyword
   |
11 |             scope.spawn( move |_| {

但是当我在 rust playground 中尝试它时,它编译没有问题 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0a10cbfd2f135975f4682c843664d539 这里有什么问题?该代码对我来说看起来很安全。

您链接到的游乐场示例使用的是 2021 版 Rust,它允许 disjoint capture in closures (and hence the closure for each thread captures only target rather than the entire t slice). If you switch to the 2018 edition,它会产生与您的问题相同的错误。

Cargo.toml 中指定您需要 2021 版(需要 rustc >= 1.56.0)。