rust学习二十.13、RUST的函数指针fn和匿名函数

张国伟  论坛元老 | 2025-4-10 18:55:12 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1643|帖子 1643|积分 4929

函数指针是一个好东西。
一、简述

函数指针就是执行一段函数代码的指针。
根据官方的说法,函数指针实现了FnOnce,FnMut,Fn特质。
由于函数指针是一种数据类型,以是rustc允许它作为函数/方法的参数,如许就给步伐设计添加了不少的灵活性.
当我估摸着,rust设计者就是为了让rust能够适应潮水:在函数/方法中直接传递匿名函数/闭包
一个典型的带有函数指针的rust函数定义如下:
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 这种定义方式实在某种程度上更加符合我的头脑方式。 在java中,我们不能那么定义,最多只能定义一个函数接口为参数,比方: void Fight(Tool tool,Target tar)
它看起来不如rust来的那么明显。rust的定义能够让我立刻意识到这是函数指针参数(意味着这是一段代码)。
当然,只要乐意,应该也可以把函数指针以不那么明显的方式定义,后文有例子.
二、示例
  1. fn add_one(x: i32) -> i32 {
  2.     x + 1
  3. }
  4. fn multiply_10(x: i32) -> i32 {
  5.     x * 10
  6. }
  7. type  FnPointer = fn(i32,i32) -> String;
  8. fn  link(f: FnPointer, x:i32,y:i32) {
  9.    let dst= f(x,y);
  10.    println!("{}",dst);
  11. }
  12. /**
  13. * 第一个参数是函数指针,fn指针实现了FnOnce,FnMut,Fn特质,所以可以接受匿名函数作为参数。
  14. */
  15. fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
  16.     f(arg) + f(arg)
  17. }
  18. fn 书本例子() {
  19.     let list_of_numbers = vec![1, 2, 3];
  20.     //利用rustc,象我这样的傻瓜也能写rust!
  21.     let list_of_strings: Vec<String> =
  22.         list_of_numbers.iter().map(|i| "0".to_owned()+&i.to_string()).collect();
  23.     println!("{:?}", list_of_strings);
  24.     let list_of_strings2: Vec<String> =
  25.         list_of_numbers.iter().map(ToString::to_string).collect();
  26.     println!("{:?}", list_of_strings2);
  27. }
  28. fn main() {
  29.     //封装再封装,就可以解决一些复杂问题,至于是否高效是另外一回事了.
  30.     let funcs=[add_one, multiply_10];
  31.     let numbers = [123, 233, 3232, 32334, 5333];
  32.     for i in 0..numbers.len() {
  33.         let answer1 = do_twice(funcs[0], numbers[i]);
  34.         let answer2=  do_twice(funcs[1], numbers[i]);
  35.         println!("({}+1)*2= {},({}*10)*2={}",numbers[i],answer1,numbers[i],answer2);   
  36.     }
  37.     // do_twice同时也能接受匿名函数,rust的解释:fn指针实现了FnOnce,FnMut,Fn特质,所以可以接受匿名函数作为参数。
  38.    
  39.     println!("\n匿名函数也能被接受作为参数的演示....");
  40.     let answer3 = do_twice(|x| x * 2+99, numbers[0]);
  41.     println!("{}经过处理后等于{}",numbers[0],answer3);
  42.     // 书本例子,让我们感兴趣是类似java等语言的流式操作
  43.     书本例子();
  44.     //类型别名
  45.     let link_to = |x:i32,y:i32| x.to_string()+&y.to_string();
  46.     link(link_to, 123,899);
  47. }
复制代码
 
上例根本模仿册本,主要演示两个问题:
1.函数指针如何定义
2.使用函数指针作为参数的函数,也能接收匿名函数为入仓
别的顺便演示了如何让函数指针看起来不那么明显(效果上类似java等一些语言),以下代码用于达成这个目的:
  1. type  FnPointer = fn(i32,i32) -> String;
  2. fn  link(f: FnPointer, x:i32,y:i32) {
  3.    let dst= f(x,y);
  4.    println!("{}",dst);
  5. }
复制代码
 
假如函数指针比较复杂,也许用上别名也不错。
输出结果:

三、函数指针的替代方案

在函数/方法中除了可以通过指定函数指针的方式来传递函数,实在还有会合方式:
1.利用特质绑定+通用类型
2.还是特质绑定+通用类型,只不过是别的一种书写形式
3.使用特质对象+动态分发dyn
以下就是例子:
[code]/** * 函数指针的替代者1  -- 利用特质绑定 */ fn batmanString>(f:T) {    let result=f(1094,101);    println!("{}",result);}/** * 函数指针的替代者2 -- 特质绑定的简化写法,rust 1.13引入的trait bound syntax */fn eggman(f:impl FnOnce(i32,i32)->String) {    let result=f(1094,103);    println!("{}",result);}/** * 函数指针的替代者3 -- 使用特质对象 */fn pigman(f:&dyn Fn(i32,i32)->String) {    let result=f(2094,103);    println!("{}",result);}fn main(){    batman(|x:i32,y:i32| x.to_string()+&y.to_string()+" 黑蝙蝠侠
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张国伟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表