fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(|x| x + 1, 5) // call
This function accepts both, closures and function pointers. It takes a function pointer as parameter type.
When should I prefer this over using a trait object, like &dyn Fn(i32) -> i32
or Box<dyn Fn(i32)-> i32>
instead of fn
fn do_twice(f: &dyn Fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(&|x| x + 1, 5) // call
or
fn do_twice(f: Box<dyn Fn(i32) -> i32>, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
When should I prefer this over using a trait object
Trait objects are not the only other option. As @DarthKotik pointed out, accepting a fn
pointer will not permit closures that capture their environment, but you can just use a normal type parameter, bounded by Fn
to accept both functions and closures, without needing to box anything:
fn do_twice<F>(f: F, arg: i32) -> i32
where
F: Fn(i32) -> i32
{
f(arg) + f(arg)
}
Or, equivalently, but avoiding an extra type variable:
fn do_twice(f: impl Fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn
type is a bare function pointer (https://doc.rust-lang.org/std/primitive.fn.html).
It won't work with the closure that captures environment and it cannot be implemented manually for your fancy type (like impl Fn for MySuperType
)
So the only reason why your examples working is the fact that it's oversimplified!
if you make it just a bit more complicated, it will fail https://gist.github.com/rust-play/2167e73325daa1e2a179505209405917
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