I'm working on an async program (a server) which uses async closures that capture their environment by value (with move) as request handlers. It means they are possibly called multiple times in their lifetime so FnOnce is not enough and they must implement Fn (or FnMut). The problem is that the compiler produces this error:
error: async closure does not implement `Fn` because it captures state from its environment
#![feature(async_closure)]
use std::future::Future;
fn give_me_a_fn_async_closure<F, Out>(f: F)
where
F: Fn() -> Out,
Out: Future<Output = ()>
{}
fn move_async_closure() {
let integer: i32 = 42;
let closure = async move || {
println!("{}", integer);
};
give_me_a_fn_async_closure(closure);
}
And the error:
Compiling playground v0.0.1 (/playground)
error: async closure does not implement `Fn` because it captures state from its environment
--> src/lib.rs:14:19
|
14 | let closure = async move || {
| ^^^^^^^^^^^^^
...
18 | give_me_a_fn_async_closure(closure);
| -------------------------- required by a bound introduced by this call
|
note: required by a bound in `give_me_a_fn_async_closure`
--> src/lib.rs:7:8
|
5 | fn give_me_a_fn_async_closure<F, Out>(f: F)
| -------------------------- required by a bound in this function
6 | where
7 | F: Fn() -> Out,
| ^^^^^^^^^^^ required by this bound in `give_me_a_fn_async_closure`
I have some workarounds in mind, but I don't understand why does is happen. Why don't async move closures implement Fn?
The standard Fn traits don't support returning borrows of the implementer; for example a closure can't return a borrow of something captured by value or a reborrow of something captured by exclusive reference. This is analogous to how the Iterator trait doesn't support lending iterators.
They AsyncFn heirarchy does support such "lending closures"... provided the return type implements Future.[1]
That doesn't really address your OP though, which doesn't need that lending quality. At a guess, they just don't try to implement the Fn traits at all in order to keep their options open. You may be able to hold the compiler's hand by creating your futures across a fn boundary instead of using an async closure or block.
I don't know if there's a good reason for that restriction. âŠī¸
Thank you guys. I can now understand why it happened.
A slightly different version of what both of you mentioned has solved my problem.
I just had to use a "normal" closure which clones/copies the moved values and returns an async block as a Future like so (I have Arcs which need to be cloned):