fn func(_: i64) -> bool {
true
}
fn func_of_func(callback: &fn(i64) -> bool, arg: i64) -> bool {
(*callback)(arg)
}
fn main() {
let is_positive = &func;
println!("{}", func_of_func(is_positive, 8));
println!("{}", func_of_func(is_positive, 8));
}
This doesn't compile:
error[E0308]: mismatched types
--> src/main.rs:9:33
|
9 | println!("{}", func_of_func(is_positive, 8));
| ^^^^^^^^^^^ expected fn pointer, found fn item
|
= note: expected reference `&fn(i64) -> bool`
found reference `&fn(i64) -> bool {func}`
Why does this error occur while I have passed a pointer, not fn
? I want to know the practical difference between using fn
and pointer to fn
.
fn(i64) -> bool
is already a function pointer, so &fn(i64) -> bool
is a reference to a function pointer. Since function pointers are Copy
, you should never have any reason to write this.
If you're writing a function that takes something function-like as an argument, you should usually use generics (or impl Fn
, as in Mike Graham's answer, which means the same thing):
fn func_of_func<F: FnOnce(i64) -> bool>(callback: F, arg: i64) -> bool {
callback(arg)
}
This means that when you call func_of_func
with a function item such as func
, callback
will be compiled to a direct function call instead of a function pointer, which is easier for the compiler to optimize.
If the function cannot be made generic (perhaps because it's a member of an object safe trait), you should usually use trait objects instead, which allows the caller to pass a closure:
fn func_of_func(callback: &dyn Fn(i64) -> bool, arg: i64) -> bool { ... }
fn func_of_func(callback: &mut dyn FnMut(i64) -> bool, arg: i64) -> bool { ... }
// using `FnOnce` requires boxing
fn func_of_func(callback: Box<dyn FnOnce(i64) -> bool>, arg: i64) -> bool { ... }
Function pointers should only be used when the function definitely cannot capture anything. They are mostly useful for FFI with C, and as type parameters to PhantomData
in generic structs.