Closures being passed as args multiple times?

@dakom for an answer illustrating this fact with examples, see Closures don't move? - #2 by Yandros

EDIT: actually you are the OP of that thread, so of course you already knew it :sweat_smile:

This is indeed the general pattern to make any 'static closure be cheaply Cloneable (instead of giving Copy-es of &f, let's "give Clones of Rc::new(f)"). It should be noted, however, that Rc<impl Fn()> : !Fn(), so a little trick is needed to get reference-counting cloning and the Fn() callable interface:

use ::std::{
    ops::Deref,
    rc::Rc,
};

fn main ()
{
    // non-Copy closure (it owns s: String which is not Copy)
    let f = {
        let s = String::from("Hello, World!");
        move || {
            println!("{}", s);
        }
    };

    fn challenge (f1: impl Fn() + 'static, f2: impl Fn() + 'static)
    {
        f1();
        f2();
    }

    // Attempt 1
    // let at_f = &f;
    // challenge(at_f, at_f); // Error, not 'static
    
    // Attempt 2
    // let at_f_static = Rc::new(f);
    // challenge(at_f_static.clone(), at_f_static); // Error: Rc<_> does not impl Fn
    
    let f = {
        let at_f_static = Rc::new(f);
        move || {
            at_f_static.deref()()
        }
    };
    challenge(f.clone(), f);
}
1 Like