无法移出“Fn”闭包中捕获的外部变量

Cannot move out of captured outer variable in an `Fn` closure

我正在尝试弄清楚如何通过通道发送一个函数,以及如何避免额外的克隆以便在另一端执行该函数。如果我删除闭包内的额外克隆操作,我会收到以下错误:

error: cannot move out of captured outer variable in an 'Fn' closure

忽略此代码完全不执行任何操作并使用全局可变静态 Sender<T> 的事实,它代表了我在给出正确的编译器错误时试图实现的目标。此代码并非运行,只是编译。

use std::ops::DerefMut;
use std::sync::{Arc, Mutex};
use std::collections::LinkedList;
use std::sync::mpsc::{Sender, Receiver};

type SafeList = Arc<Mutex<LinkedList<u8>>>;
type SendableFn = Arc<Mutex<(Fn() + Send + Sync + 'static)>>;
static mut tx: *mut Sender<SendableFn> = 0 as *mut Sender<SendableFn>;

fn main() {
    let list: SafeList = Arc::new(Mutex::new(LinkedList::new()));
    loop {
        let t_list = list.clone();
        run(move || {
            foo(t_list.clone());
        });
    }
}

fn run<T: Fn() + Send + Sync + 'static>(task: T) {
    unsafe {
        let _ = (*tx).send(Arc::new(Mutex::new(task)));
    }
}

#[allow(dead_code)]
fn execute(rx: Receiver<SendableFn>) {
    for t in rx.iter() {
        let mut guard = t.lock().unwrap();
        let task = guard.deref_mut();
        task();
    }
}

#[allow(unused_variables)]
fn foo(list: SafeList) { }

是否有更好的方法来解决该错误and/or我应该通过渠道发送函数的另一种方式?

Fn() 的问题是您可以多次调用它。如果您移出捕获的值,则该值在下一次调用时将不再可用。您需要一个 FnOnce() 来确保调用闭包也从其中移出,因此它已经消失并且无法再次调用。

没有办法Arc<Mutex<(FnOnce() + Send + Sync + 'static)>>。这将再次要求您静态地保证在调用该函数后,没有其他人可以再次调用它。你不能,因为其他人可能有另一个 Arc 指向你的 FnOnce。您可以做的是将其装箱并作为 Box<FnOnce() + Send + Sync + 'static> 发送。 Box.

永远只有一个拥有者

FnOnce() 的问题在于,当它在 Box 中时您不能真正调用它,因为那需要将它移出 Box 并调用它。但是我们不知道它的大小,所以我们不能把它移出Box。将来 Box<FnOnce()> 闭包可能会直接可用。

"Luckily"这个问题出现的比较频繁,所以有FnBox. Sadly this requires nightly to work. Also I couldn't figure out how to use the function call syntax that is described in the docs, but you can manually call call_box on the Box<FnBox()>. Try it out in the Playground