I have the following simplified sample producing a problem with moving a clone of a string to a closure. Somehow my usual cloning, Arc/Mutex use did not help here either. So I am a bit puzzled what could be a possible resolution here. Any pointers on further reading etc?
use futures::Future;
struct A {
v:String,
}
impl A {
pub async fn m(&self) {
let cl=self.v.clone();
b(|s| async move {
let cl2=cl.clone();
println!("Hello{}{}",cl2,s);
});
}
}
#[tokio::main]
async fn main() {
let a=A { v: String::from(" ") };
a.m().await;
println!("Later use: HELLO{}WORLD!",a.v);
}
async fn b<F,G>(f:F)
where F: Fn(String) -> G + Send + 'static + Sync + Clone,
G: Future<Output=()> + Send + 'static,
{
f(String::from("World!")).await
}
The error message:
Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `cl`, a captured variable in an `Fn` closure
--> src/main.rs:11:22
|
10 | let cl=self.v.clone();
| -- captured outer variable
11 | b(|s| async move {
| _______---____________^
| | |
| | captured by this `Fn` closure
12 | | let cl2=cl.clone();
| | --
| | |
| | variable moved due to use in generator
| | move occurs because `cl` has type `String`, which does not implement the `Copy` trait
13 | | println!("Hello{}{}",cl2,s);
14 | | });
| |_____^ move out of `cl` occurs here
For more information about this error, try `rustc --explain E0507`.
error: could not compile `playground` due to previous error
It seems that you want FnOnce(), not Fn() for the trait bound. (You're also missing an .await, but that's irrelevant from the perspective of this error.) Playground.
The trait bound comes from a lib unfortunately, so I cannot change that. The lib requires an Fn as it plans to call my method multiple times in a background thread.
No, it's not "making the closure async". That's merely an async block inside a perfectly regular closure. (The type annotations of a closure are only of the form |args: Types| -> RetType; everything else beyond that is part of the body/return value.)
"Async" from the point of the type system isn't really special, it just means that the expression has type impl Future<Output = …>, and closures have no async declaration. (A proper async |…| closure form is being developed on nightly, if one can believe the compiler.)