我试图弄清楚如何通过一个通道发送一个函数,以及如何避免额外的克隆以便在另一端执行该函数。如果我在闭包内删除了额外的克隆操作,我会收到以下错误:
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) { }
有没有更好的方法来解决这个错误和/或我应该通过渠道发送功能的其他方式?
答案 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