当然可以:
fn fun_test(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
fun_test(5, ×2);
}
由于这是 Rust,您必须考虑到 ownership and lifetime of the closure。
TL;DR;基本上有 3 种类型的闭包(可调用对象):
-
Fn:不能修改捕获的对象。
-
FnMut:它可以修改它捕获的对象。
-
FnOnce:最受限制的。只能调用一次,因为调用时它会消耗自身及其捕获。
详情请见When does a closure implement Fn, FnMut and FnOnce?
如果您使用的是像闭包这样简单的指向函数的指针,那么捕获集是空的,并且您具有 Fn 风格。
如果你想做更多花哨的东西,那么你将不得不使用 lambda 函数。
在 Rust 中有正确的指向函数的指针,它们的工作方式与 C 中的一样。它们的类型例如是 fn(i32) -> i32。 Fn(i32) -> i32、FnMut(i32) -> i32 和 FnOnce(i32) -> i32 实际上是特征。指向函数的指针总是实现所有这三个,但 Rust 也有闭包,可能会或可能不会转换为指向函数的指针(取决于捕获集是否为空),但它们确实实现了其中一些特征。
例如,上面的例子可以展开:
fn fun_test_impl(value: i32, f: impl Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_dyn(value: i32, f: &dyn Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn fun_test_ptr(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
let y = 2;
//static dispatch
fun_test_impl(5, times2);
fun_test_impl(5, |x| 2*x);
fun_test_impl(5, |x| y*x);
//dynamic dispatch
fun_test_dyn(5, ×2);
fun_test_dyn(5, &|x| 2*x);
fun_test_dyn(5, &|x| y*x);
//C-like pointer to function
fun_test_ptr(5, times2);
fun_test_ptr(5, |x| 2*x); //ok: empty capture set
fun_test_ptr(5, |x| y*x); //error: expected fn pointer, found closure
}