Closures in API design – theoretical limitations and best practices?

We can work around fix this by using the unstable feature try_trait_v2_residual (#91285) and by forcing the "fallibility wrapper" (e.g. Result, Option, etc.) to be identical to the one used by the Future::Output of the return type of the closure:

    pub async fn try_new_async<F, R>(
        mut callback: F,
    ) -> <R::Residual as Residual<Self>>::TryType
    where
        F: for<'a> internal::Callback<&'a str, R>,
        R: Try<Output = String>,
        R::Residual: Residual<Self>,
        <R::Residual as Residual<Self>>::TryType:
            Try<Output = Self> + FromResidual<<R as Try>::Residual>,
    {
        let mut output = Vec::with_capacity(KEYS.len());
        for key in KEYS.iter().copied() {
            output.push(callback(key).await?);
        }
        <R::Residual as Residual<Self>>::TryType::from_output(Self {
            output,
        })
    }

(Playground) (Playground) edit: Also got rid of unnecessary turbofish type annotation in main.

But… well…