无法移出“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
我正在尝试弄清楚如何通过通道发送一个函数,以及如何避免额外的克隆以便在另一端执行该函数。如果我删除闭包内的额外克隆操作,我会收到以下错误:
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