Understanding Fn / FnOnce closures
Solution 1:
Let's desugar the closures manually.
struct Closure1 {
client: BasicClient,
}
impl FnOnce<()> for Closure1 {
type Output = BasicClient;
extern "rust-call" fn call_once(self, (): ()) -> BasicClient {
<Self as Fn<()>>::call(&self, ())
}
}
impl FnMut<()> for Closure1 {
extern "rust-call" fn call_mut(&mut self, (): ()) -> BasicClient {
<Self as Fn<()>>::call(&*self, ())
}
}
impl Fn<()> for Closure1 {
extern "rust-call" fn call(&self, (): ()) -> BasicClient {
<BasicClient as Clone>::clone(&self.client)
}
}
struct Closure2 {
client: BasicClient,
}
impl FnOnce<()> for Closure2 {
type Output = BasicClient;
extern "rust-call" fn call_once(self, (): ()) -> BasicClient {
self.client
}
}
fn with_client(
client: BasicClient,
) -> impl Filter<Extract = (BasicClient,), Error = Infallible> + Clone {
warp::any().map(Closure1 { client })
}
fn with_client(
client: BasicClient,
) -> impl Filter<Extract = (BasicClient,), Error = Infallible> + Clone {
let clone = <BaseClient as Clone>::clone(&clone);
warp::any().map(Closure1 { client: clone })
}
Like you see, the problem is not that we move client
into the closure. The problem is that we move it out of the closure. When you move out of something, you must have ownership of the data: thus, FnOnce
. The fact that you're creating the closure with a clone does not matter. But when you clone inside the closure, you only use shared references - and thus you don't need ownership, or even exclusive access - thus Fn
.