为什么通过移动捕获 Arc 使我的闭包 FnOnce 而不是 Fn
Why does capturing an Arc by move make my closure FnOnce not Fn
在下面的示例中,我使用 Arc 从请求处理程序引用服务器状态,但编译器将闭包设为 FnOnce
。感觉我在做正确的事,因为每个闭包都拥有对状态的强引用。为什么这不起作用?有哪些选项可以使其发挥作用? 等其他问题表明类似这样的工作,但我正在如图所示制作每个闭包克隆,但仍然出现错误。
#![feature(async_closure)]
#[derive(Default, Debug)]
struct State {}
impl State {
pub async fn exists(&self, key: &str) -> bool {
true
}
pub async fn update(&self, key: &str) {}
}
#[tokio::main]
async fn main() {
use warp::Filter;
use std::sync::Arc;
let state: Arc<State> = Arc::default();
let api = warp::post()
.and(warp::path("/api"))
.and(warp::path::param::<String>().and_then({
let state = Arc::clone(&state);
async move |p: String| {
let x = state.exists(&p);
if x.await {
Ok(p)
} else {
Err(warp::reject::not_found())
}
}
}))
.and_then({
let state = Arc::clone(&state);
async move |id: String| {
state.update(&id).await;
Result::<String, warp::Rejection>::Ok("".to_owned())
}
});
warp::serve(api).run(([127, 0, 0, 1], 0)).await;
}
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:25:13
|
23 | .and(warp::path::param::<String>().and_then({
| -------- the requirement to implement `Fn` derives from here
24 | let state = Arc::clone(&state);
25 | async move |p: String| {
| _____________^^^^^^^^^^^^^^^^^^^^^^_-
| | |
| | this closure implements `FnOnce`, not `Fn`
26 | | let x = state.exists(&p);
27 | | if x.await {
28 | | Ok(p)
... |
31 | | }
32 | | }
| |_____________- closure is `FnOnce` because it moves the variable `state` out of its environment
好吧,异步闭包不稳定,所以这可能是一个错误。我认为当异步块捕获 Arc
时它会消耗它,所以闭包实际上只能被调用一次。我的意思是,异步闭包是某种生成器:每次调用它时,它都会构建一个未来,而未来会保留捕获的值。
作为变通方法,您可以这样写:
let state = Arc::clone(&state);
move |p: String| {
let state = Arc::clone(&state);
async move {
let x = state.exists(&p);
//...
}
}
在闭包内但在 async
块之前进行另一个克隆可确保您可以根据需要多次调用闭包。
我认为实际上 Warp::Filter
应该首先接受 FnOnce
,但我不知道 warp
足以确定。
在下面的示例中,我使用 Arc 从请求处理程序引用服务器状态,但编译器将闭包设为 FnOnce
。感觉我在做正确的事,因为每个闭包都拥有对状态的强引用。为什么这不起作用?有哪些选项可以使其发挥作用?
#![feature(async_closure)]
#[derive(Default, Debug)]
struct State {}
impl State {
pub async fn exists(&self, key: &str) -> bool {
true
}
pub async fn update(&self, key: &str) {}
}
#[tokio::main]
async fn main() {
use warp::Filter;
use std::sync::Arc;
let state: Arc<State> = Arc::default();
let api = warp::post()
.and(warp::path("/api"))
.and(warp::path::param::<String>().and_then({
let state = Arc::clone(&state);
async move |p: String| {
let x = state.exists(&p);
if x.await {
Ok(p)
} else {
Err(warp::reject::not_found())
}
}
}))
.and_then({
let state = Arc::clone(&state);
async move |id: String| {
state.update(&id).await;
Result::<String, warp::Rejection>::Ok("".to_owned())
}
});
warp::serve(api).run(([127, 0, 0, 1], 0)).await;
}
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:25:13
|
23 | .and(warp::path::param::<String>().and_then({
| -------- the requirement to implement `Fn` derives from here
24 | let state = Arc::clone(&state);
25 | async move |p: String| {
| _____________^^^^^^^^^^^^^^^^^^^^^^_-
| | |
| | this closure implements `FnOnce`, not `Fn`
26 | | let x = state.exists(&p);
27 | | if x.await {
28 | | Ok(p)
... |
31 | | }
32 | | }
| |_____________- closure is `FnOnce` because it moves the variable `state` out of its environment
好吧,异步闭包不稳定,所以这可能是一个错误。我认为当异步块捕获 Arc
时它会消耗它,所以闭包实际上只能被调用一次。我的意思是,异步闭包是某种生成器:每次调用它时,它都会构建一个未来,而未来会保留捕获的值。
作为变通方法,您可以这样写:
let state = Arc::clone(&state);
move |p: String| {
let state = Arc::clone(&state);
async move {
let x = state.exists(&p);
//...
}
}
在闭包内但在 async
块之前进行另一个克隆可确保您可以根据需要多次调用闭包。
我认为实际上 Warp::Filter
应该首先接受 FnOnce
,但我不知道 warp
足以确定。