0

我试图让一个异步闭包在and_then过滤器中工作Warp

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

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
4

2 回答 2

0

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

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意味着只能保证闭包执行一次。

于 2020-10-01T08:21:08.800 回答
0

制作Manifestimplement后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然后异步块拥有该数据并且可以对其进行引用,而不必担心在数据被释放后执行未来。

于 2020-10-02T02:27:34.200 回答