As I understand it, functions each get their own unique type similar to how closures work. These special function types are called "fn items". This helps the compiler do a bunch of optimizations safely, but occasionally causes confusing type errors. Fn items can always be coerced to function pointers, which behave how you'd expect. In many places the coercion is automatic, but type inference gets in the way of the coercion here.
You can coerce the functions to function pointers explicitly if you really want to be able to pass them both as the same type with as fn(&mut Cursive)
This code now looks a bit weird to me. The only way to call this function now is either with the same closure or function twice or with a function pointer. Other options are practically nonexistent since Copy prevents boxed trait objects (FnOnce or similar) or mutably borrowed trait objects, and &dyn Fn(...) is mostly ruled out by the 'static.
So either, the separate parameter F3 should be kept, or the function can be made fully monomorphic to always expect function pointers. (The choice depends on whether capturing closures [capturing Copyable data] should be allowed, and - more importantly - on whether the monomorphization for each given pair of function types, and avoiding dynamic function calls, is seen as a relevant performance benefit.) As a positive side effect, either approach would make the calls-site straightforward again.
which I assume is not supposed to be a common use case here, but maybe I'm wrong? ↩︎
Maybe focus on my conclusion first, if I didn’t present the argument (leading to that conclusion) well enough:
The point is that the use-case of using function pointers is (essentially) the only use-case left (except for those where two copies of the same function/closure are passed). So if only function-pointers are to be used anyways, the signature could as well be written
To further explain the argument, in case the rest was not clear enough before, either: For closures and fn items, if the types are the same then the closure/function is the same, too, which is a not too useful case. The only implementors of FnOnce besides closures and fn items are
dyn FnOnce/dyn FnMut/dyn Fn trait objects
Box<T>, &mut T, &T for T being any of these cases (possibly recursively)
The additional bounds rule out most of those. The Copy bound rules out Box<T> and &mut T, and the 'static bound rules out (most reasonable cases) of &T, too.The trait objects can never be passed alone, so by Box<T>, &mut T, &T being eliminated, they are out of the equation, too; thus only function pointers are left.
(And technically something like &'static dyn Fn(…) would work, too, but I would have never seen such a thing before.)