无法让异步闭包与 Warp::Filter 一起使用



我正试图从Warp获得一个在and_then过滤器中工作的异步闭包。

这是我能想到的最小的例子,我有理由相信我没有遗漏任何重要的细节:

use std::{convert::Infallible, sync::Arc, thread, time};
use tokio::sync::RwLock;
use warp::Filter;
fn main() {
let man = Manifest::new();
let check = warp::path("updates").and_then(|| async move { GetAvailableBinaries(&man).await });
}
async fn GetAvailableBinaries(man: &Manifest) -> Result<impl warp::Reply, Infallible> {
Ok(warp::reply::json(&man.GetAvailableBinaries().await))
}
pub struct Manifest {
binaries: Arc<RwLock<Vec<i32>>>,
}
impl Manifest {
pub fn new() -> Manifest {
let bins = Arc::new(RwLock::new(Vec::new()));
thread::spawn(move || async move {
loop {
thread::sleep(time::Duration::from_millis(10000));
}
});
Manifest { binaries: bins }
}
pub async fn GetAvailableBinaries(&self) -> Vec<i32> {
self.binaries.read().await.to_vec()
}
}

我正在使用:

[dependencies]
tokio = { version = "0.2", features = ["full"] }
warp = { version = "0.2", features = ["tls"] }

错误为:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:9:48
|
9 |     let check = warp::path("updates").and_then(|| async move { GetAvailableBinaries(&man).await });
|                                       -------- ^^^^^^^^^^^^^ ------------------------------------ closure is `FnOnce` because it moves the variable `man` out of its environment
|                                       |        |
|                                       |        this closure implements `FnOnce`, not `Fn`
|                                       the requirement to implement `Fn` derives from here

使Manifest实现Clone后,可以通过在清单对象被克隆时进行平衡来修复错误:

fn main() {
let man = Manifest::new();
let check = warp::path("updates").and_then(move || {
let man = man.clone();
async move { get_available_binaries(&man).await }
});
warp::serve(check);
}

这将man移动到传递给and_then的闭包中,然后在每次执行闭包时向异步块提供man的克隆。异步块然后拥有该数据,并且可以引用该数据,而不用担心在数据被释放后会执行该数据。

我不确定这是你想要的,但这个解决方案是为我构建的:

use std::{convert::Infallible, sync::Arc, thread, time};
use tokio::sync::RwLock;
use warp::Filter;
fn main() {
let man = Manifest::new();
let check = warp::path("updates").and_then(|| async { GetAvailableBinaries(&man).await });
}
async fn GetAvailableBinaries(man: &Manifest) -> Result<impl warp::Reply, Infallible> {
Ok(warp::reply::json(&man.GetAvailableBinaries().await))
}
#[derive(Clone)]
pub struct Manifest {
binaries: Arc<RwLock<Vec<i32>>>,
}
impl Manifest {
pub fn new() -> Manifest {
let bins = Arc::new(RwLock::new(Vec::new()));
thread::spawn(move || async {
loop {
thread::sleep(time::Duration::from_millis(10000));
//mutate bins here
}
});
Manifest { binaries: bins }
}
pub async fn GetAvailableBinaries(&self) -> Vec<i32> {
self.binaries.read().await.to_vec()
}
}

这里的move是编译器发出有关签名的警告的原因:let check = warp::path("updates").and_then(|| async move { GetAvailableBinaries(&man).await });。这意味着这个闭包中引用的所有内容都将被移到闭包的上下文中。在这种情况下,编译器不能保证闭包是Fn,而只能保证是FnOnce,这意味着闭包只能保证执行一次。

最新更新