I'm trying to use a for loop to iterate over a vector of functions and execute each function at each step.
fn f1(i: i32) -> i32 {
i * 2
}
fn f2(i: i32) -> i32 {
i * 4
}
fn main() {
let mut arr: Vec<|i32| -> i32> = Vec::new();
arr.push(f1);
arr.push(f2);
for f in arr.iter() {
println!("{}", f(1));
}
}
But the attempted execution of f(1)
gives this error:
error: expected function, found '&|i32| -> i32'
I guess in putting the functions in the vector their type is mutated and no longer works like a normal function. Is there a way to transform it back, or am I missing something?
As of Rust 1.x, unboxed closures are the only kind of closures in the language, and they don't need a feature flag. Moreover, static functions can easily be converted to unboxed closures. Therefore, the correct way to call functions from a vector of functions is:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<&dyn Fn(i32) -> i32> = vec![&f1, &f2];
for f in &arr {
println!("{}", (f)(1));
}
}
I've used Fn()
closures which can access their environment through a shared reference, so it is sufficient to iterate the vector by reference. If I had used a FnMut()
closure, I would have had to use iteration by mutable reference:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let p1 = &mut f1;
let p2 = &mut f2;
let mut arr: Vec<&mut dyn FnMut(i32) -> i32> = vec![p1, p2];
for f in &mut arr {
println!("{}", (f)(1));
}
}
A similar idea holds for FnOnce()
and iteration by value, although here we need to use Box
to own the closure:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<Box<dyn FnOnce(i32) -> i32>> = vec![Box::new(f1), Box::new(f1)];
for f in arr {
println!("{}", (f)(1));
}
}
Alternatively, if you know that you only work with static functions, it is possible to store pointers to them directly, without using closure traits:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<fn(i32) -> i32> = vec![f1, f2];
for f in &arr {
println!("{}", (f)(1));
}
}
While f1
and f2
actually have different incompatible types, they are automatically coerced to the general function pointer type fn(i32) -> i32
when used in appropriate context, like in the example above.
Because static functions don't have any environment, you can freely clone references to them and call them through any kind of reference. This is probably the way to go if you only need static functions.
This answer was updated for Rust 1.x; older versions of the answer remain in the edit history.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With