How can I pass a struct method for a closure

Hello guys, I 'v got this little issue about passing a method as parameter when a closure is required. There is the obvious solution of creating a closure which just redirects to the method call, but I just wonder if there is a better approach.

If I declare a function like this:

fn apply(x: i64, y: i64, callback: &mut impl FnMut(i64, i64) -> ()) {
    callback(x, y);
}        

I have a couple of valid options to pass the callback parameter to it such:

  apply(100i64, 100i64, &mut |x, y| println!("Closure {} {}", x, y));
  apply(100i64, 100i64, &mut SomeHandler::some_handler);
  apply(100i64, 100i64, &mut some_func);

However I would like to pass to it a struct method. For example if I have something like:

#[derive(Default)]
pub struct SumHandler {
    sum: i64,
}

impl SumHandler {
    pub fn sum_handler(&mut self, x: i64, y: i64) {
        self.sum += x;
        self.sum += y;
        println!("Sum handler {} {}", x, y);
    }
}

I could call it like this:

fn main() {
    let mut sum_h = SumHandler::default();
    //works but is does an indirection
    apply(100i64, 100i64, &mut |x, y| sum_h.sum_handler(x, y));
}

However this creates a closure which calls my method, instead to refer the method directly.
Is it anyway to refer that method from the given struct instance directly?
Something in the line of (None of this do work):

    //not working but I would like something like this
    //apply(100i64, 100i64,sum_h::sum_handler);
    //apply(100i64, 100i64,sum_h.sum_handler);
    //apply(100i64, 100i64,SumHandler::sum_h::sum_handler);
    //apply(100i64, 100i64,SumHandler::sum_handler(&sum_h));

You can check the full code on rust playground here

Thanks a lot!

I think the approach of wrapping it in a closure is the right approach here, since sum_handler() is a function that takes 3 arguments whereas the apply function requires a FnMut of 2 arguments. Depending on what you're doing, you could make it simpler by not creating the SumHandler type:

fn main() {
    let mut sum : i64 = 0;
    let sum_handler = |x, y| {
        sum += x;
        sum += y;
        println!("Sum handler {} {}", x, y);
    }
    apply(100i64, 100i64, &mut sum_handler);
}

If you require a larger SumHandler type, then you have to wrap an instance of the type, or a method call on it, in a closure, following the pattern you already have.

Another alternative, if you're willing to use unstable features, would be to implement FnMut directly for SumHandler, making sum_h itself into the required closure (you could then attach methods to access information stored in it, such as sum). However, access to the call_mut() method, and hence the ability to implement this trait, is currently unstable, so you'll need to use the nightly compiler if you want to use this approach.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.