我正在尝试编写一个通用的set_interval
函数助手:
pub fn set_interval<F, Fut>(mut f: F, dur: Duration)
where
F: Send + 'static + FnMut() -> Fut,
Fut: Future<Output = ()> + Send + 'static,
{
let mut interval = tokio::time::interval(dur);
tokio::spawn(async move {
// first tick is at 0ms
interval.tick().await;
loop {
interval.tick().await;
tokio::spawn(f());
}
});
}
在从类内部调用它之前,这可以正常工作:
fn main() {}
struct Foo {}
impl Foo {
fn bar(&self) {
set_interval(|| self.task(), Duration::from_millis(1000));
}
async fn task(&self) {
}
}
self
不是'static
,由于tokio::task
,我们不能将生存期参数限制为小于'static
的值。
是否可以修改set_interval
实现,使其在这种情况下工作?
Link to playground
附言:试图
let instance = self.clone();
set_interval(move || instance.task(), Duration::from_millis(1000));
但我也得到一个错误:错误:捕获的变量无法转义FnMut
闭包主体
2条答案
按热度按时间b4lqfgs41#
是否可以修改set_interval的实现,使其在这种情况下工作?
虽然
spawn
-ingf()
也没有帮助,因为它排除了简单的“callback owns the object”解决方案(因为你需要callback和future来拥有对象,或者只需要future)。我想这就剩下两个解决办法了:
1.将所有内容转换为共享可变性
Arc
,回调函数拥有一个Arc
,然后在每次tick时克隆该Arc
并将克隆对象移到未来(task
方法)。1.让future(
task
)从某个外部源获取对象,而不是在某个外部源上调用,这样中间回调就不需要做任何事情,或者回调可以完成获取并将其移到future,同样的diff。顺便说一下,在这一点上,直接创建future,但允许克隆它是有意义的,所以
set_interval
将不接受回调,而是接受一个可克隆的future,它将spawn()
克隆它存储的future,而不是重新创建它们。nuypyhwy2#
正如@Masklinn所提到的,您可以克隆Arc来实现这一点。注意,克隆Arc * 不会 * 克隆底层数据,而只是指针,因此这样做通常是可以的,并且不会对性能产生重大影响。
下面是一个示例。下面的代码将生成错误
async block may outlive the current function, but it borrows data, which is owned by the current function
:Rust建议将
move
添加到两个异步块,但这将导致借用错误,因为会有多个所有权。要解决这个问题,我们可以为每个任务克隆Arc,* 然后 * 将
move
关键字添加到异步块: