如何将 Rust 函数作为参数传递?

我可以传递一个函数作为参数吗? 如果不行,有什么好的替代方法吗?

我尝试了一些不同的语法,但我没有找到正确的一个。我知道我可以这样做:

fn example() {
let fun: fn(value: i32) -> i32;
fun = fun_test;
fun(5i32);
}


fn fun_test(value: i32) -> i32 {
println!("{}", value);
value
}

但这不是将函数作为参数传递给另一个函数:

fn fun_test(value: i32, (some_function_prototype)) -> i32 {
println!("{}", value);
value
}
90558 次浏览

你当然可以:

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, &times2);
}

由于这是锈,你必须考虑到 关闭的所有权和生命周期

基本上有3种闭包(可调用对象) :

  1. 它不能修改它捕获的对象。
  2. 它可以修改它捕获的对象。
  3. FnOnce: 最受限制的。只能调用一次,因为当它被调用时,它会消耗它自己和它的捕获。

有关详细信息,请参阅 闭包什么时候实现 Fn、 FnMut 和 FnOnce?

如果使用类似闭包的简单指针函数,则捕获集为空,并且具有 Fn风格。

如果您想做更多花哨的事情,那么您将不得不使用 lambda 函数。

在 Rust 中有指向函数的正确指针,它们的工作方式与 C 语言中的一样。他们的类型是例如 fn(i32) -> i32Fn(i32) -> i32FnMut(i32) -> i32FnOnce(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, &times2);
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
}

另一个答案中概述的 FnFnMutFnOnce了结类型。关闭其作用域的函数类型。

除了传递闭包外,Rust 还支持传递简单(非闭包)函数,如下所示:

fn times2(value: i32) -> i32 {
2 * value
}


fn fun_test(value: i32, f: fn(i32) -> i32) -> i32 {
println!("{}", f (value));
value
}


fn main() {
fun_test (2, times2);
}

这里是 函数指针类型

如果您不需要一个完整的闭包,那么使用函数类型通常会更简单,因为它不需要处理那些闭包生命周期细节。