Hmm, are you suggesting that without move, the closure is borrowing the reference (instead of the function itself) and that reference has a lifetime of its own aside from the lifetime of the value it borrows? I initially thought that, but in my snippet, f in the closure seems to have type &'static F and not &&'static F.
This is also true. The body of the closure uses f however it wants, and the compiler analyzes it to decide whether to implicitly borrow or move f. In this case because the body of the closure only calls f, which doesn't require moving it, the compiler decides the closure doesn't need ownership. move basically tells the compiler "No, I actually want you to move all the captured variables into this closure, even if the body only uses them by reference".
I was going to add a post similar to this, saying that this should work too because FnOnce's call is self bound, but then I ran into this weird behavior:
Your code works, but for some weird reason Rust needs some help in understaing which specific type and/or which specific trait the func() call expression is using.
With feature(fn_traits), for instance, using the fully-qualified call syntax makes your code work.
And in stable Rust, a helper function achieves what that fully-qualified syntax does:
fn call<F> (func: &'_ F)
-> Box<dyn Fn() + '_>
where
// equivalent to `F : Fn()`
for<'a>
&'a F : FnOnce()
,
{
return Box::new(move || do_call(func));
// where
fn do_call (f: impl FnOnce()) { f() }
}
As to why Rust "brain-farts" on that one, I don't really know