函数指针是一个好东西。
一、简述
函数指针就是执行一段函数代码的指针。
根据官方的说法,函数指针实现了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的定义能够让我立刻意识到这是函数指针参数(意味着这是一段代码)。
当然,只要乐意,应该也可以把函数指针以不那么明显的方式定义,后文有例子.
二、示例
- fn add_one(x: i32) -> i32 {
- x + 1
- }
- fn multiply_10(x: i32) -> i32 {
- x * 10
- }
- type FnPointer = fn(i32,i32) -> String;
- fn link(f: FnPointer, x:i32,y:i32) {
- let dst= f(x,y);
- println!("{}",dst);
- }
- /**
- * 第一个参数是函数指针,fn指针实现了FnOnce,FnMut,Fn特质,所以可以接受匿名函数作为参数。
- */
- fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
- f(arg) + f(arg)
- }
- fn 书本例子() {
- let list_of_numbers = vec![1, 2, 3];
- //利用rustc,象我这样的傻瓜也能写rust!
- let list_of_strings: Vec<String> =
- list_of_numbers.iter().map(|i| "0".to_owned()+&i.to_string()).collect();
- println!("{:?}", list_of_strings);
- let list_of_strings2: Vec<String> =
- list_of_numbers.iter().map(ToString::to_string).collect();
- println!("{:?}", list_of_strings2);
- }
- fn main() {
- //封装再封装,就可以解决一些复杂问题,至于是否高效是另外一回事了.
- let funcs=[add_one, multiply_10];
- let numbers = [123, 233, 3232, 32334, 5333];
- for i in 0..numbers.len() {
- let answer1 = do_twice(funcs[0], numbers[i]);
- let answer2= do_twice(funcs[1], numbers[i]);
- println!("({}+1)*2= {},({}*10)*2={}",numbers[i],answer1,numbers[i],answer2);
- }
- // do_twice同时也能接受匿名函数,rust的解释:fn指针实现了FnOnce,FnMut,Fn特质,所以可以接受匿名函数作为参数。
-
- println!("\n匿名函数也能被接受作为参数的演示....");
- let answer3 = do_twice(|x| x * 2+99, numbers[0]);
- println!("{}经过处理后等于{}",numbers[0],answer3);
- // 书本例子,让我们感兴趣是类似java等语言的流式操作
- 书本例子();
- //类型别名
- let link_to = |x:i32,y:i32| x.to_string()+&y.to_string();
- link(link_to, 123,899);
- }
复制代码
上例根本模仿册本,主要演示两个问题:
1.函数指针如何定义
2.使用函数指针作为参数的函数,也能接收匿名函数为入仓
别的顺便演示了如何让函数指针看起来不那么明显(效果上类似java等一些语言),以下代码用于达成这个目的:- type FnPointer = fn(i32,i32) -> String;
- fn link(f: FnPointer, x:i32,y:i32) {
- let dst= f(x,y);
- println!("{}",dst);
- }
复制代码
假如函数指针比较复杂,也许用上别名也不错。
输出结果:
三、函数指针的替代方案
在函数/方法中除了可以通过指定函数指针的方式来传递函数,实在还有会合方式:
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企服之家,中国第一个企服评测及商务社交产业平台。 |