How can an operator be passed as a function parameter?

Trying to solve an online exercise, I would like to write a closure which takes an operator ('-' or '+') as a parameter. So far I got this definition and calling of the closure inside a function which is given 'minutes' as a parameter (minutes: &mut i32):

let mut massage_minutes = | f: &(dyn for<'r> Fn(&'r mut i32, i32) -> i32) | {
    *minutes = f(minutes, 60);
    //... more irrelevant code
}

And I try to call it like this:

while *minutes < 0 {
    massage_minutes(&std::ops::Add::add);
    //... more irrelevant code
}

But this results in:

error[E0631]: type mismatch in function arguments
--> src/lib.rs:49:29
|
49 | massage_minutes(&std::ops::Add::add);
| ^^^^^^^^^^^^^^^^^^^
| |
| expected signature of for<'r> fn(&'r mut i32, i32) -> _
| found signature of fn(_, _) -> _
|
= note: required for the cast to the object type dyn for<'r> std::ops::Fn(&'r mut i32, i32) -> i32

error[E0271]: type mismatch resolving for<'r> <fn(_, _) -> <_ as std::ops::Add<_>>::Output {<_ as std::ops::Add<_>>::add} as std::ops::FnOnce<(&'r mut i32, i32)>>::Output == i32
--> src/lib.rs:49:29
|
49 | massage_minutes(&std::ops::Add::add);
| ^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'r, found concrete lifetime
|
= note: required for the cast to the object type dyn for<'r> std::ops::Fn(&'r mut i32, i32) -> i32

What's wrong here?

1 Like

Add::add is defined as <Lhs as Add<Rhs>>::add : fn(Lhs, Rhs) -> Lhs::Output. Notice that there is no lifetime quantification. Lifetime are qualified at the outer

for<'a> (add<'a> : fn(&'a i32, &'a i32) -> i32)
add_inner : for<'a> (fn('a i32, &'a i32) -> i32)

Semantically, two are isomorphic to each other. It can be converted via a closure.

fn f(op: &dyn for<'a> Fn(&'a i32, &'a i32) -> i32) {}

fn main() {
    f(&|x, y| x + y);
}

You might want to use AddAssign::add_assign rather than Add::add.

2 Likes

Thanks a lot, that worked!