fn item 和 fn pointer 之间的实际区别是什么?
What's the practical difference between fn item and fn pointer?
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));
}
这不编译:
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}`
为什么我传递的是指针而不是 fn
时会出现此错误?我想知道使用 fn
和指向 fn
的指针之间的实际区别。
你应该可以用
解决这个问题
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));
}
或者更直接地不添加间接级别
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));
}
更常见的是使用 Fn
特征,它的好处是允许闭包和函数
fn func(x: i64) -> bool {
true
}
fn func_of_func(callback: impl FnOnce(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));
}
fn(i64) -> bool
是already a function pointer,所以&fn(i64) -> bool
是对函数指针的引用。由于函数指针是 Copy
,你永远不应该写这个。
如果你正在编写一个函数,它接受一些东西 function-like 作为参数,你通常应该使用泛型(或 impl Fn
,如 ,这意味着同样的事情):
fn func_of_func<F: FnOnce(i64) -> bool>(callback: F, arg: i64) -> bool {
callback(arg)
}
这意味着当你用func
这样的函数项调用func_of_func
时,callback
将被编译为直接函数调用而不是函数指针,这样更容易供编译器优化。
如果函数不能被通用化(可能是因为它是对象安全特征的成员),您通常应该使用特征对象来代替,这允许调用者传递闭包:
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 { ... }
只有当函数绝对不能捕获任何东西时才应该使用函数指针。它们主要用于使用 C 的 FFI,并作为泛型结构中 PhantomData
的类型参数。
参考资料
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));
}
这不编译:
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}`
为什么我传递的是指针而不是 fn
时会出现此错误?我想知道使用 fn
和指向 fn
的指针之间的实际区别。
你应该可以用
解决这个问题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));
}
或者更直接地不添加间接级别
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));
}
更常见的是使用 Fn
特征,它的好处是允许闭包和函数
fn func(x: i64) -> bool {
true
}
fn func_of_func(callback: impl FnOnce(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));
}
fn(i64) -> bool
是already a function pointer,所以&fn(i64) -> bool
是对函数指针的引用。由于函数指针是 Copy
,你永远不应该写这个。
如果你正在编写一个函数,它接受一些东西 function-like 作为参数,你通常应该使用泛型(或 impl Fn
,如
fn func_of_func<F: FnOnce(i64) -> bool>(callback: F, arg: i64) -> bool {
callback(arg)
}
这意味着当你用func
这样的函数项调用func_of_func
时,callback
将被编译为直接函数调用而不是函数指针,这样更容易供编译器优化。
如果函数不能被通用化(可能是因为它是对象安全特征的成员),您通常应该使用特征对象来代替,这允许调用者传递闭包:
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 { ... }
只有当函数绝对不能捕获任何东西时才应该使用函数指针。它们主要用于使用 C 的 FFI,并作为泛型结构中 PhantomData
的类型参数。