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

时间:2015-11-11 23:56:54

标签: rust function-pointers channel

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

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) { }

有没有更好的方法来解决这个错误和/或我应该通过渠道发送功能的其他方式?

1 个答案:

答案 0 :(得分:15)

Fn()的问题是您可以多次调用它。如果您移出捕获的值,则下次调用时该值将不再可用。你需要一个FnOnce()来确保调用闭包也会移出它,所以它已经消失了,不能再被调用了。

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

FnOnce()的问题在于,Box中您无法真正调用它,因为这需要将其移出Box并调用它。但是我们不知道它的大小,因此我们无法将其移出Box。将来Box<FnOnce()>闭包可能会直接使用。

&#34;幸运的是&#34;这个问题经常发生,所以有FnBox。可悲的是,这需要每晚工作。此外,我无法弄清楚如何使用文档中描述的函数调用语法,但您可以在call_box上手动调用Box<FnBox()>。在Playground

中试一试