← Back to context

Comment by BlackFly

21 days ago

The biggest friction I experience with respect to rust closures is their inability to be generic: I cannot implement a method that takes a closure generic over its argument(s).

So then I'm forced to define a trait for the function, define a struct (the closure) to store the references I want to close over, choose the mutability and lifetimes, instantiate it manually and pass that. Then the implementation of the method (that may only be a few lines) is not located inline so readability may suffer.

You most definitely can.

    fn foo<F, T>(f: F)
    where
        F: Fn(T),
        T: ToString,
    {
        f("Hello World")
    }

Or did I not understand what you meant?

  • Something like this isn’t possible

        fn foo(f: impl for<T: ToString> Fn(T)) {
            f(“Hello World”);
            f(3.14);
        }
    
        fn main() {
            f(|x| println!("{}", x.to_string());
        }
    

    The workaround:

        trait FnToString {
            fn call(&self, x: impl ToString);
        }
    
        fn foo(f: impl FnToString) {
            f.call("Hello World");
            f.call(3.14);
        }
    
        struct AnFnToString;
        impl FnToString for AnFnToString {
            fn call(&self, x: impl ToString) {
                println!("{}", x.to_string());
            }
        }
    
        fn main() {
            foo(AnFnToString);
        }

    • Ha, yes, I see what you mean now. That's not really the closure's fault but monomorphization of the foo function. The specific thing you want to do would require boxing the value, or do more involved typing.