我是否可以将函数作为Rust中的参数传递(可能是),如果可以的话,我可以这样做。
如果你不能,这是一个很好的选择。
我尝试了一些语法,但我没有得到
我知道我可以做到这一点
..//
let fun: fn(value: i32) -> i32;
fun = funTest;
fun(5i32);
..//
fn funTest(value: i32) -> i32 {
println!("{}", value);
value
}
但不是将函数作为参数传递给另一个函数
..//
fn funTest(value: i32, (some_function_prototype)) -> i32 {
println!("{}", value);
value
}
答案 0 :(得分:63)
当然可以:
fn funTest(value: i32, f: &Fn(i32) -> i32) -> i32 {
println!("{}", f(value));
value
}
fn times2(value: i32) -> i32 {
2 * value
}
fn main() {
funTest(5, ×2);
}
但这是Rust,所以你必须考虑ownership and lifetime of the closure。
TL; DR;基本上有3种类型的闭包(可调用对象):
Fn
:最通用的,它是一个纯函数。FnMut
:它可以修改它捕获的对象。FnOnce
:最受限制的。只能被调用一次,因为它被调用时会消耗自身及其捕获。如果你使用像闭包那样的简单指针,那么捕获集是空的,你有Fn
的味道。
如果你想做更多花哨的东西,那么你将不得不使用lambda函数。
更新:经过一段时间学习Rust之后,我需要强烈要求解决这个问题。
在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
}
答案 1 :(得分:12)
Fn
,FnMut
和FnOnce
是闭包类型。关闭其范围的函数类型。
除了传递闭包之外,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);
}
fn(i32) -> i32
这里是function pointer type。
如果你不需要一个完整的闭包而不是使用函数类型通常更简单,因为它不必处理那些关闭生命周期的特性。