Rust Closure 闭包解析(匿名函数)

文章目录

  • Rust Closure 闭包解析(匿名函数)
  • 正文
    • 1. 简单闭包 - 纯粹的匿名函数
    • 2. 捕获上下文 & FnOnce、FnMut、Fn 类型验证
  • 其他资源
    • 参考连接
    • 完整代码示例

正文

闭包与匿名函数是现代语言对与函数式编程范式常见的实现,与 JavaScript 惊人的相似的是对于外部上下文的变量捕捉等特性,下面我们就来介绍如何在 Rust 中使用闭包,同时它也将作为 Rust 多线程编程中的重要基础知识之一

1. 简单闭包 - 纯粹的匿名函数

首先我们先介绍第一种,最简单的闭包用法,在代码行中创建一个行内匿名函数

  • /src/anonymous_function.rs

基本的函数的类型是 Fn,我们创建一个结构体用于保存一个函数与其运行

extern crate rand;use std::thread;
use std::time::Duration;
use std::ops::Fn;
use rand::random;struct FnCache<T> where T: Fn(u32) -> u32 {calculation: T,value: Option<u32>,
}

然后定义创建构造函数与数据访问函数

impl<T> FnCache<T> where T: Fn(u32) -> u32 {fn new(calculation: T) -> FnCache<T> {FnCache {calculation,value: None,}}fn value(&mut self, arg: u32) -> u32 {match self.value {Some(value) => value,None => {let value = (self.calculation)(arg);self.value = Some(value);value}}}
}

接下来我们就能够在行内调用构造函数并传入匿名函数作为可配置的算法过程

fn generate_task(intensity: u32) -> bool {let mut expensive_closure = FnCache::new(|num| {println!("calculating slowly...");thread::sleep(Duration::from_secs(2));println!("done!");num});if intensity < 20 {println!("intensity = {}, keep working", expensive_closure.value(intensity));false} else {println!("intensity = {}, enough", intensity);true}
}

我们可以看到 Rust 使用 |params| { statements } 的语法结构来表示匿名函数

最后我们做一个小循环进行测试

pub fn test() {println!(">>>>> anonymous_function");let mut count = 1;loop {let i: u32 = random();let random_intensity = i % 30;let done = generate_task(random_intensity);if done || count >= 3 {break;}count += 1;}
  • 输出
>>>>> anonymous_function
calculating slowly...
done!
intensity = 7, keep working
intensity = 20, enough

当然实际上我们使用 fn 关键字定义的一般函数实际上也拥有一样的类型签名

fn simple_fn(x: u32) -> u32 {println!("simple_fn({})", x);x
}pub fn test() {println!("\n! test normal function as Fn");let mut cache = FnCache::new(simple_fn);println!("cache.value(1) = {}", cache.value(1));println!("cache.value(2) = {}", cache.value(2));println!();
}
  • 输出
! test normal function as Fn
simple_fn(1)
cache.value(1) = 1
cache.value(2) = 1

2. 捕获上下文 & FnOnce、FnMut、Fn 类型验证

然而闭包最强大的部分除了可以自由在运行时创建函数之外,就是能够捕获上下文环境的变量这个特性,就能够将一些已经消失的作用域中的变量透过闭包捕获并私有化

下面我们使用三个例子来演示使用闭包捕获上下文变量,同时顺便验证 FnOnce、FnMut、Fn 这三个类型的不同之处

  • /src/capture_environment.rs

第一个例子创建一个比较函数,并能够提前绑定参数

fn capture_var(x: u32) -> Box<dyn Fn(u32) -> bool> {Box::new(move |y: u32| y == x)
}pub fn test() {println!(">>>>> capture_environment");println!("! Fn test");let equal_one = capture_var(1);println!("equal_one(3) = {}", (*equal_one)(3));println!("equal_one(2) = {}", (*equal_one)(2));println!("equal_one(1) = {}", (*equal_one)(1));
}
  • 输出
>>>>> capture_environment
! Fn test
equal_one(3) = false
equal_one(2) = false
equal_one(1) = true

第二个例子演示了一个计数器的实现,修改了上下文的变量因此用到了 FnMut 类型

fn counter() -> Box<dyn FnMut(bool) -> u32> {let mut val = 0;Box::new(move |incr| {if incr {val += 1;}val})
}pub fn test() {println!("! FnMut test");let mut increment = counter();println!("increment() = {}", (*increment)(true));println!("increment() = {}", (*increment)(true));println!("increment() = {}", (*increment)(false));
}
  • 输出
! FnMut test
increment() = 1
increment() = 2
increment() = 2

第三个例子则是测试只能调用一次的函数签名 FnOnce

fn once<T>(f: T) -> Box<dyn Fn() -> u32> where T: FnOnce() -> u32 {let val = f();Box::new(move || val)
}pub fn test() {println!("! FnOnce test");let gettter = once(|| {3});println!("get = {}", (*gettter)());
}
  • 输出
! FnOnce test
get = 3

其他资源

参考连接

Title Link
Closures: Anonymous Functions that Can Capture Their Environment - The Rust Programming Language https://doc.rust-lang.org/book/ch13-01-closures.html

完整代码示例

https://github.com/superfreeeee/Blog-code/tree/main/back_end/rust/rust_closure

Rust Closure 闭包解析(匿名函数)相关推荐

  1. php 匿名方法,PHP基于Closure类创建匿名函数的方法详解

    本文实例讲述了PHP基于Closure类创建匿名函数的方法.分享给大家供大家参考,具体如下: Closure 类 用于代表匿名函数的类. 匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象. ...

  2. 闭包(匿名函数) php

    php中的闭包,之前不理解.以前项目中虽然有用到,也是别人怎么用,自己也跟着怎么用,也没具体去看一下,时间长了就忘了,也不知道闭包是怎么回事.今天网上搜集了关于php闭包相关的文章,看了7,8篇,干货 ...

  3. 初探swift语言的学习笔记三(闭包-匿名函数)

    作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29353019 转载请注明出处 如果觉得文章对你有所帮助,请通过留言 ...

  4. php _invoke 闭包,PHP新特性之闭包、匿名函数

    闭包 闭包是什么? 1).闭包和匿名函数在PHP5.3中被引入. 2).闭包是指在创建时封装函数周围状态的函数,即使闭包所在的环境不存在了,闭包封装的状态依然存在,这一点和Javascript的闭包特 ...

  5. Python3进阶--正则表达式、json、logging日志配置、数据库操作、枚举、闭包、匿名函数和高阶函数、time、datetime

    第一章 变量.常用循环体.代码结构.代码练习 第二章 列表.元组等数据结构.字符串驻留机制及字符串格式化操作 第三章 函数.面向对象.文件操作.深浅拷贝.模块.异常及捕获 第四章 项目打包.类和对象高 ...

  6. 初探swift语言的学习笔记(闭包 - 匿名函数或block块代码)

    很多高级语言都支持匿名函数操作,在OC中的block也为大家所熟悉,然面在swift里好像是被重新作了一个定义,不叫匿名函数,或 block了,而叫闭包(closure).下面配合代码来理解一下swi ...

  7. 好程序员前端教程之JavaScript闭包和匿名函数的关系详解...

    好程序员前端教程之JavaScript闭包和匿名函数的关系详解 本文讲的是关于JavaScript闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包.下面一起来看看文章分析,希望你 ...

  8. Python 中的闭包、匿名函数、decorator 装饰器与python的偏函数

    Python中的闭包 def calc_sum(lst):def lazy_sum():return sum(lst)return lazy_sum 像这种内层函数引用了外层函数的变量(参数也算变量) ...

  9. JavaScript正则、闭包和匿名函数

    笔记 一.继承补充 1.对象冒充 借助call或apply方法来修改父类的构造函数中的this指向,来完成属性的继承. function Student(name) {this.name = name ...

最新文章

  1. Windows Server 2016 笔记
  2. linux 设置开机命令提示符,centos设置开机默认命令行启动
  3. 灰度值取值范围_灰度实战(二):Apollo配置中心(2)
  4. java 内存泄漏_Java开发者必须知道的内存泄漏问题
  5. 论文浅尝 | WWW2022 - “知识提示”之知识约束预训练微调
  6. java ajax传输图片_Java使用Ajax实现跨域上传图片功能
  7. 公司新来了一个质量工程师,说团队要保证 0 error,0 warning
  8. oracle 查看 统计更新时间,oracle查看和更新统计表的信息
  9. cad坐标提取插件_如何快速地将CAD里的坐标提取到Excel中?最简单的方法你知道吗?...
  10. 网上支付(支付宝/银联)
  11. 生成交叉表的SQL基本语句
  12. NanoMsg框架C++的相关函数介绍
  13. SEO网站优化注意5个小细节,降低网站跳出率
  14. java 读取浏览器_JAVA读取文件流,设置浏览器下载或直接预览操作
  15. 选择合适的 Go 字符串拼接方式
  16. 华大单片机HC32L130/HC32L136从机IIC通信
  17. Java中如何实现添加用户信息_如何通过Java客户端在Active Directory中创建新用户并将其添加到现有组...
  18. 仿文献高级检索多关键词查询的网页实现
  19. JAVA分页代码实例
  20. 除尘机器人毕业_一种除尘机器人的制作方法

热门文章

  1. 移动端自适应布局和响应式页面兼容移动端布局
  2. 对数据增删改查的Sql语句
  3. mwc 2018 oracle,MWC2018 | 一口气扫遍MWC2018 谁敢说移动设备创新不足?
  4. Windows xp 在VMware虚拟机上面安装的详细步骤
  5. [Debug]内存问题的一些调试方法
  6. CS8.1Type-C拓展坞HUB芯片|专门用于Type-C 扩展坞设计芯片
  7. 【报告分享】2020年单身青年居行报告-58安居客(附下载)
  8. 将特征转换为正态分布的一种方法示例
  9. 抖音直播间商品怎么上架?低粉新号快速引流玩法来了!
  10. PHP、JAVA、NET 编程技术对比分析