我正在尝试弄清楚如何通过 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) { }
是否有更好的方法来解决该错误和/或我应该通过 channel 发送函数的其他方式?
最佳答案
Fn()
的问题是你可以多次调用它。如果您移出捕获的值,则该值在下一次调用时将不再可用。你需要一个FnOnce()
以确保调用闭包也移出它,所以它已经消失并且不能再次调用。
没有办法得到 Arc<Mutex<(FnOnce() + Send + Sync + 'static)>>
.这将再次要求您静态地保证在调用该函数后,没有其他人可以再次调用它。你不能,因为其他人可能有另一个 Arc
指向你的 FnOnce
.您可以做的是将其装箱并作为 Box<FnOnce() + Send + Sync + 'static>
发送。 . Box
的拥有者只有一个.
FnOnce()
的问题是的,当它在 Box
中时,你真的不能调用它吗? ,因为这需要将其移出 Box
并调用它。但是我们不知道它的大小,所以我们不能将它移出 Box
。 .以后Box<FnOnce()>
闭包可能会直接可用。
“幸运的是”这个问题发生的频率更高,所以有 FnBox
.遗憾的是,这需要每晚才能工作。我也不知道如何使用文档中描述的函数调用语法,但您可以手动调用 call_box
在 Box<FnBox()>
上.在 Playground 中试用
关于rust - 无法移出 `Fn` 闭包中捕获的外部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33662098/