rust函数指针和闭包异同探索随笔

//rust需要在编译时确定某个类型的值究竟会占据多少内存,而且同一类型的所有值都必须使用相同大小的内存,否则编译无法进行。

//对于DST动态大小类型在编译器期间无法得知其确切大小,所以直接定义此种类型的变量,rust编译无法通过!

//那么如何应对?基本上采用:引用、智能指针、impl等方式即可解决。

//rust函数是一等公民,当然可以作为参数传递存储返回。

//rust函数指针fn是rust本身具有的数据类型之一,而闭包是trait,确切说是三个trait: Fn/FnMut/FnOnce.

//因为rust函数指针impl了全部三个闭包trait, 我们总是可以把函数指针用作实参传递给一个声明接受闭包的函数。

//rust函数指针可以指向"非捕获型闭包" , 我的理解:在rust中"捕获型闭包"因为需要记录被捕获的值,所以需要创建一个结构体记录之!所以"捕获型闭包"实际上是一个结构体;

//而"非捕获型闭包"实际上就是一个函数,因为他需要的值都是通过调用传参获得,不需要记录什么,所以只需要一个函数指针记录执行入口即可。

//切记:闭包可以捕获外部变量,而函数不可以。

//当然以上是我查阅资料和代码试验后的个人理解,

//水平有限,若有谬误,希望指正。

//详细解释请仔细阅读rust编译报错提示信息即可。

//rust函数指针例子

fn add_one(x:i32) -> i32 {

x+1

}

//case1: 把函数指针用作函数参数,传参, 编译通过。

fn do_twice(f: fn(i32)->i32, arg:i32)->i32{

f(arg) + f(arg)

}

//case2:把函数指针用作函数返回值,编译通过。

fn take_a_function_pointer() -> fn(i32)->i32 {

add_one

}

//rust闭包例子

//Fn/FnMut/FnOnce是闭包的三个trait.

//case3: 通过trait object返回闭包,编译通过。

fn returns_closure_by_trait_object()-> Box<dyn Fn(i32)->i32> {

Box::new(|x| x+1)

}

//case4: 编译错误:rust编译器无法获知闭包trait编译期已知大小,请使用Box或者impl.

//fn returns_closure3()-> Fn(i32)->i32 {

// |x| x+1

//}

//case5: 把函数指针用作返回值类型,可以返回函数或非捕获型闭包,编译通过!

fn returns_closure2_by_fn_pointer() -> fn(i32)->i32 {

|x| x+1

}

//case6: 编译错误:rust编译器无法获知闭包trait编译期已知大小,请使用泛型或者impl或者&dyn trait object.

//fn take_closure(f: Fn(i32)->i32, arg:i32) -> i32{

// f(arg)

//}

//case7:编译通过,通过函数指针类型形参接受非捕获型闭包或函数。

fn take_fn_or_closure_by_function_pointer(f: fn(i32)->i32, arg:i32) -> i32{

f(arg)

}

//case8:编译通过,通过闭包trait形参接受函数指针和闭包

fn take_fn_or_closure_by_closure_trait(f: impl Fn(i32)->i32, arg:i32) -> i32 {

f(arg)

}

fn main() {

//for case1.

let answer = do_twice(add_one, 5);

println!("the function pointer answer is : {}", answer);

//for case2.

println!("-----------------------");

let fp = take_a_function_pointer();

let answer2 = fp(5);

println!("to return function pointer answer is :{}", answer2);

//----------------------------------

//for case3.

let ac = returns_closure_by_trait_object();

let answer3 = ac(5);

println!("to return Box dyn closure answer is: {}", answer3);

//for case5.

println!("-----------------------");

let acp = returns_closure2_by_fn_pointer();

let answer3 = acp(5);

println!("to return closure by the function pointer answer is : {}", answer3);

//for case7.

println!("-----------------------");

//函数指针可以指向"非捕获型闭包",我理解"捕获型闭包"是通过:获取所有权(包括值复制)、可变借用、不可变借用等手段而非调用传参方式获取值。打开注释,注意编译报错信息。

let answer4 = take_fn_or_closure_by_function_pointer(|x|x+1, 5);

println!("to take closure by function pointer answer is : {}", answer4);

let answer5 = take_fn_or_closure_by_function_pointer(add_one, 5);

println!("to take function by fn pointer answer is: {}", answer5);

//函数指针不可以指向"捕获型闭包",编译报错。

//let a = 5;

//let answer6 = take_fn_or_closure_by_function_pointer(|x| x+a, 5);

//let a_str = String::from("hello world!");

//let answer7 = take_fn_or_closure_by_function_pointer(|x| {println!("{}",a_str); x+1}, 5);

//for case8.

println!("-----------------------");

let answer8 = take_fn_or_closure_by_closure_trait(|x|x+1, 5);

println!("to take a closure by the closure trait, answer is: {}", answer8);

let answer9 = take_fn_or_closure_by_closure_trait(add_one, 5);

println!("to take a function by the closure trait, answer is: {}", answer9);

}

相关推荐
我很好我还能学16 分钟前
【面试篇 9】c++生成可执行文件的四个步骤、悬挂指针、define和const区别、c++定义和声明、将引用作为返回值的好处、类的四个缺省函数
开发语言·c++
蓝婷儿37 分钟前
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
开发语言·python·学习
渣渣盟1 小时前
基于Scala实现Flink的三种基本时间窗口操作
开发语言·flink·scala
糯米导航1 小时前
Java毕业设计:办公自动化系统的设计与实现
java·开发语言·课程设计
糯米导航1 小时前
Java毕业设计:WML信息查询与后端信息发布系统开发
java·开发语言·课程设计
MessiGo2 小时前
Javascript 编程基础(5)面向对象 | 5.1、构造函数实例化对象
开发语言·javascript·原型模式
大霞上仙2 小时前
nonlocal 与global关键字
开发语言·python
galaxy_strive2 小时前
绘制饼图详细过程
开发语言·c++·qt
黑客老李3 小时前
JavaSec | SpringAOP 链学习分析
java·运维·服务器·开发语言·学习·apache·memcached
开开心心就好3 小时前
高效Excel合并拆分软件
开发语言·javascript·c#·ocr·排序算法·excel·最小二乘法