The problem
I want to create a function (chain) that takes a function f: Fn(i32) -> i32, number n and returns a new function g: Fn(i32) -> i32 that applys f to it’s input n times.
For example: chain(3, f) should return a function eqvivalent to: |x| f(f(f(x))).
Here is my attempt at achieving this (similar code works in Python):
fn chain(n: i32, f: Box<dyn Fn(i32) -> i32>) -> Box<dyn Fn(i32) -> i32> {
println!("This is not printed when the resulting function is called!");
match n {
1 => f,
_ if n > 1 => {
let g = chain(n - 1, f);
Box::new(move |x| g(f(x)))
},
_ => Box::new(|x| x),
}
}
The compiler produces some errors about borrowing moved values, and I can’t figure out how to fix them.
error[E0382]: use of moved value: `f`
--> src/lib.rs:7:22
|
1 | fn chain(n: i32, f: Box<dyn Fn(i32) -> i32>) -> Box<dyn Fn(i32) -> i32> {
| - move occurs because `f` has type `Box<dyn Fn(i32) -> i32>`, which does not implement the `Copy` trait
...
6 | let g = chain(n - 1, f);
| - value moved here
7 | Box::new(move |x| g(f(x)))
| ^^^^^^^^ - use occurs due to use in closure
| |
| value used here after move
Background
I want to create a program that takes an arithmetic expression in string form and then creates a function that can evaluate the expression. For example: "2*x+3" should result in a function |x| add(mul(2,x),3). The resulting function is called many times and should execute as fast as possible.
>Solution :
You use f twice. You cannot. You cannot use a reference either, since the function is local and you cannot return a reference to it.
The simplest fix is to replace Box with Rc:
fn chain(n: i32, f: Rc<dyn Fn(i32) -> i32>) -> Rc<dyn Fn(i32) -> i32> {
println!("This is not printed when the resulting function is called!");
match n {
1 => f,
_ if n > 1 => {
let g = chain(n - 1, Rc::clone(&f));
Rc::new(move |x| g(f(x)))
},
_ => Rc::new(|x| x),
}
}
However, this incurs an overhead of a dynamic function call for each operation, an I think a simple match to the operation will be faster.