What is the difference if I define a function parameter as reference or as value (other that the parameter is moved)? Is there a performance difference?
In this case I cannot remove the & before dyn and must pass the function as reference, as otherwise the compiler complains the size cannot be known at compile time. This makes sense, as anyhow only the address of the function is passed (or not?).
If you're passing F as a generic parameter, your binary will have different assembly for each different F. Compiler will see exactly what is F, may inline or optimize in some other way specifically for each and every F. This is a default choose you should use.
dyn Fn is an unsized object, and &dyn Fn is a fat pointer to that object. All calls are dispatched through a virtual table and are slower, sometimes significantly. On the other side, your calculate will not be duplicated across the binary (at the cost that compiler will not optimize it so much in respect to the function).
So do not use &dyn Fn until you know what you're doing. As long as you don't, use calculate<F: Fn()>(f: F) or, equivalently, calculate(f: impl Fn()) (just nicer syntax).
The first requires a reference to a function. The second does not require a reference, and is more general (because the caller can pass a reference if they want).
Typically, the second is preferable as it is easier to call. However, if calculate were recursive, you would have to use the first so that f_result_analyzer can be passed down through the recursion by copy.
const DO_NOTHING: Option<fn(&ResultBatch) -> i32> = None;
// ...
calculate(&[], &config, DO_NOTHING);
// This also works but who would want to type it more than once
calculate(&[], &config, None::<fn(&ResultBatch) -> i32>);
Incidentally, you can probably use F: FnMut(&ResultBatch) -> i32, which is more flexible for callers. Or maybe even FnOnce.
I would suggest having 2 function, one with no callback and another with. That one without callback will call that with callback and pass None::<fn(&ResultBatch) -> i32>.