This code generates an error cannot move out of "s1", a captured variable in an Fn closure, even though I've specified that the closure is move. Instead shouldn't the compilation error be Expected an Fn() closure, found FnOnce()?
Hm, the error message is indeed not overly helpful. If you change the structure of your program, the error messages becomes more clear:
fn main() {
let s1 = "asd".to_owned();
let c = move || {
dbg!(s1);
};
f1(c);
}
fn f1<F: Fn()>(t: F) {
t();
}
Error:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:4:13
|
4 | let c = move || {
| ^^^^^^^ this closure implements `FnOnce`, not `Fn`
5 | dbg!(s1);
| -- closure is `FnOnce` because it moves the variable `s1` out of its environment
...
8 | f1(c);
| -- - the requirement to implement `Fn` derives from here
| |
| required by a bound introduced by this call
|
note: required by a bound in `f1`
--> src/main.rs:11:10
|
11 | fn f1<F: Fn()>(t: F) {
| ^^^^ required by this bound in `f1`
I think this is a side-effect of how the inference/implementation of a closure is guided by ascription. Basically, because the trait bound of f1 demands a Fn() implementation, the compiler attempts a Fn() implementation when the closure is a direct argument of the call to f1. But when it is not a direct argument, the attempted implementation is based on the closure body.
But regardless, I agree that the diagnostic output should be improved.