我可以在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 }
rodrigo.. 86
你当然可以:
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,因此您必须考虑关闭的所有权和生命周期.
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 }
请注意,使用泛型而不是特征对象(即`
有趣的是,从(接口)(调用者)的角度来看,“ FnOnce”实际上是最通用的特征-它接受所有闭包,无论它们是读取,修改还是获取已捕获状态的所有权。`FnMut`的限制更严格,它不接受拥有已捕获对象所有权的闭包(但它仍允许状态的修改)。Fn是限制性最强的,因为它不接受修改其捕获状态的闭包。因此,要求`&Fn`对`funTest`调用者施加最大的限制,而对如何在其中调用`f`提供最小的限制。 (3认同)
ArtemGr.. 20
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
这是一个函数指针类型.
如果你不需要一个完整的闭包而不是使用函数类型通常更简单,因为它不必处理那些闭包生命周期的特性.
你当然可以:
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,因此您必须考虑关闭的所有权和生命周期.
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 }
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
这是一个函数指针类型.
如果你不需要一个完整的闭包而不是使用函数类型通常更简单,因为它不必处理那些闭包生命周期的特性.