Hey, everyone. I'm starting to use Rust, and I'm having some difficulties with the compiler while trying to create a function which accepts another function as parameter. Currently, I'm doing this to avoid duplicating code in my Lambda function:
this is a peculiar situation, where you hit the limitation of the sugared Fn trait syntax. I vaguely know the reason but cannot explain it clearly.
in this example, since the function_handler() doesn't need to capture the parameter (it is unused at all), you can workaround it by tweak the signature of function_handler a bit.
but I assume the client parameter is actually used in real code, so this workaround is more involed, namely, you can use a boxed future for the Fn bound which can specify higher ranked lifetimes, and you must manually box the future in the function_handler() function instead of relying on the async fn desugar.
you have a generic parameter Fut, which is required to be the output of F. Because Fut is a separate generic parameter, its value cannot depend on what F does. But the F you want to use, function_handler, returns a future type which does depend on F — specifically, the future uses the borrow &Client and thus its type must contain the lifetime of that borrow.
The Fn bound on F is implicitly a HRTB — desugared it is for<'a> F: Fn(Request, &'a Client) -> Fut. The <F, Fut> pattern works only in cases where F's bound is not HRTB.
Instead, you must write your required bounds in some way that does not make use of a separate Fut parameter. The new AsyncFn trait does this, but has its own limitations; to work on stable you can use helper traits like those provided by async_fn_traits (or write your own for this specific case) which only specify the future as an associated type, which can therefore stay inside the scope of the implicit for<'a> in the bound on F.