7赞
411
当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在Rust中,如何将函数作为参数传递?》经验,为你挑选了2个好方法。

我可以在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) -> 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, ×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
}

请注意,使用泛型而不是特征对象(即``而不是`(f:&Fn ...)`更加惯用.这是有原因的 - 泛型将导致静态调度,而特质对象需要动态调度. (5认同)

有趣的是,从(接口)(调用者)的角度来看,“ FnOnce”实际上是最通用的特征-它接受所有闭包,无论它们是读取,修改还是获取已捕获状态的所有权。`FnMut`的限制更严格,它不接受拥有已捕获对象所有权的闭包(但它仍允许状态的修改)。Fn是限制性最强的,因为它不接受修改其捕获状态的闭包。因此,要求`&Fn`对`funTest`调用者施加最大的限制,而对如何在其中调用`f`提供最小的限制。 (3认同)


ArtemGr.. 20

Fn,FnMutFnOnce在对方的回答概括,是封闭的类型.关闭其范围的函数类型.

除了传递闭包之外,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这是一个函数指针类型.

如果你不需要一个完整的闭包而不是使用函数类型通常更简单,因为它不必处理那些闭包生命周期的特性.



1> rodrigo..:

你当然可以:

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) -> 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, ×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
}


请注意,使用泛型而不是特征对象(即``而不是`(f:&Fn ...)`更加惯用.这是有原因的 - 泛型将导致静态调度,而特质对象需要动态调度.
有趣的是,从(接口)(调用者)的角度来看,“ FnOnce”实际上是最通用的特征-它接受所有闭包,无论它们是读取,修改还是获取已捕获状态的所有权。`FnMut`的限制更严格,它不接受拥有已捕获对象所有权的闭包(但它仍允许状态的修改)。Fn是限制性最强的,因为它不接受修改其捕获状态的闭包。因此,要求`&Fn`对`funTest`调用者施加最大的限制,而对如何在其中调用`f`提供最小的限制。

2> ArtemGr..:

Fn,FnMutFnOnce在对方的回答概括,是封闭的类型.关闭其范围的函数类型.

除了传递闭包之外,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这是一个函数指针类型.

如果你不需要一个完整的闭包而不是使用函数类型通常更简单,因为它不必处理那些闭包生命周期的特性.


推荐阅读
author-avatar
手浪用户2602901267
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有