Search code examples
pointersruststructfunc

Is there any way to save pointer of any function in the struct?


I've been wondering is there any way to get pointer of function with unspecified arguments and output types (unspecification of output type isn't as necessary as arguments). For example, in C++ when you are spawning new thread you pass function pointer without any specification.

As I see it can solved with trait that would represent fn in the same way as std::marker::Tuple represents Tuple object.

Example:

struct Cont <F: FN_TRAIT> {
    func: F,
}

impl<F: FN_TRAIT> Cont <F> {
    fn new(func: F) -> Self {
        Self { func: func }
    }

    fn start(&self, args: dyn std::marker::Tuple) {
        self.func.call(args);
    }
}

fn temp(a: i32, b: i32) {
    println!("{}", a + b);
}

fn main() {
    let a = Cont::new(temp);
    a.start((0,1));
}

I tried to find the way to represent fn with trait in the struct and then call it with std::marker::Tuple as arguments.


Solution

  • You can do it with generics mostly the same as C++ does it:

    struct Cont<Args, F> {
        args: Args,
        fun: F,
    }
    
    impl<Args, F> Cont<Args, F> {
        fn new (fun: F, args: Args) -> Self {
            Cont { args, fun, }
        }
    }
    
    impl<A, R, F: FnOnce (A) -> R> Cont<(A,), F> {
        fn call (self) -> R {
            (self.fun) (self.args.0)
        }
    }
    
    impl<A0, A1, R, F: FnOnce (A0, A1) -> R> Cont<(A0, A1), F> {
        fn call (self) -> R {
            (self.fun) (self.args.0, self.args.1)
        }
    }
    
    fn main() {
        let c1 = Cont::new (|x| 2*x, (0,));
        let c2 = Cont::new (|x, y| x+y, (2, 3));
        println!("{} {}", c1.call(), c2.call());
    }
    

    Playground

    Except that you need to add an implementation for each possible number of arguments (this can probably be simplified with a macro).