写点什么

5 分钟速读之 Rust 权威指南(二十一)闭包

用户头像
码生笔谈
关注
发布于: 2021 年 06 月 11 日
5分钟速读之Rust权威指南(二十一)闭包

闭包

闭包这个名字在前端学的时候比较晕,因为闭包 rust 中的闭包与 JS 的闭包完全不是一个东西,rust 中的闭包是一种可以存入变量或作为参数传递给其他函数的匿名函数。

定义闭包

像定义变量一样定义闭包,想象一下 TS 中的箭头函数,区别只是把包裹参数的圆括号换成了两条竖线:


let add = |a: u32, b: u32| -> u32 {  a + b};add(1, 2); // 3
复制代码


闭包并不强制要求标注参数和返回值的类型,编译器会自行推断:


let add = |a, b| {  a + b};
复制代码


如果闭包体内只有一个表达式,可以更加简写:


let add = |a, b| a + b;
复制代码


函数不支持对函数体以外的变量进行引用,而闭包中允许对外部变量进行引用:


let a = 1;let b = 2;let add = || {  a + b};add(); // 3
复制代码


函数不支持引用外部变量:


let a = 1;let b = 2;fn add() -> i32 {  a + b // error,找不到变量a,b};add();
复制代码

在结构体中使用闭包

在结构体中的闭包需要声明 trait 约束:


// 声明闭包的约束为:Fn(u32) -> u32struct Cacher<T: Fn(u32) -> u32> {  calculation: T,  value: Option<u32>}
impl<T> Cacher<T: Fn(u32) -> u32> { fn new(calculation: T) -> Cacher<T> { Self { calculation, value: Option::None } } fn value(&mut self, arg: u32) -> u32 { match self.value { Option::Some(v) => v, Option::None => { // 调用闭包,为了区分自身的方法,需要加括号 (self.calculation)(2); self.value = Option::Some(arg); arg } } }}
复制代码

闭包的 trait 约束种类

闭包有三种类型,对应对于外界变量的引用方式:


  • FnOnce 将引用的外界变量所有权移动进闭包。

  • Fn 可以从环境中不可变地借用值。

  • FnMut 可以从环境中可变地借用值并对它们进行修改。


利用 move 关键字强制将引用的外部变量的所有权转移到闭包中


let a = String::from("1");let b = String::from("1");let cmp = move|| a == b;
println!("{}", cmp());println!("{}", a); // error,变量被移动了println!("{}", b); // error,变量被移动了
复制代码


笔者在学习的过程中有看过这样一篇介绍生命周期和闭包的相关文章,感兴趣的话可以去阅读:闭包与所有权

发布于: 2021 年 06 月 11 日阅读数: 9
用户头像

码生笔谈

关注

欢迎关注「码生笔谈」公众号 2018.09.09 加入

前端、Rust干货分享,一起成为更好的Javascripter & Rustacean

评论

发布
暂无评论
5分钟速读之Rust权威指南(二十一)闭包