附有丰富的 [例程]
rust【闭包】在内存里被保存为【结构体】。概括地讲,我这篇文章就是总结了上述(3)与(4)项中提到的“条件”关系于一张表格,并基于该表格展开论述。
let test = || println!("生成类 + 实例化 + 变量绑定 一条龙服务");),rustc就会为该【闭包】连续做如下几件事情struct】的实例instance,而不是【闭包struct】的类型type。timing要更晚一些)[例程1]。Fn / FnMut / FnOnce trait之一的struct(类型)--- 下文皆称其为【闭包struct】struct】的唯一实例。struct】实例绑定给【变量绑定语句】等号=左侧的具名变量(比如,上面例子中的test)。struct】的【成员方法Fn::call / FnMut::call_mut / FnOnce::call_once】封装了【闭包】要执行的业务逻辑。struct】的若干【字段】保存了被【闭包】【捕获】的外部变量。而具体内容小结: 因为,在不同的代码上下文中,
所以,每个【闭包】皆对应于一个独一无二的且匿名的struct类型。而所有【闭包struct】的共同点就是:
Fn / FnMut / FnOnce trait之一。虽然Rust Programming Language权威指南是以【闭包】对【外部变量】【捕获方式】的分类为切入点,来讲解【闭包】,但是我发现:若完全依赖这套解释标准,我对某些【闭包】代码的理解会遇到不自恰的尴尬。为了避免“思维-凑数”,我摸索了一套辅助手段来帮助解读【闭包】代码。该方法是以【闭包】业务程序对【外部变量】【处理方式】的分类为起点,进而判断【闭包】的行为特性。
首先,【捕获方式】影响的是【闭包】【外部变量】的生命周期。即,
drop之后,【外部变量】是否可恢复被其次,【处理方式】描述的是【闭包】业务程序如何使用【外部变量】(是借入,还是所有权转移)。它的影响范围更广,包括:
接着,【处理方式】【捕获方式】【〔外部变量〕生命周期】【〔闭包〕执行次数】,这四个要素之间的相互关系可概括为:
move关键字能开启“后门”:绕过【处理方式】强制设置【捕获方式】,定制【外部变量】生命周期更形象、详细的描述可被展开为如下表格:

对上表内脚注 [1] [2] [3] [4] 的展开解释如下:
struct】实例被以let mut绑定至变量。这是由rust【继承可修改】语言特性决定的。即,若要修改某个struct的字段值,那么该字段所属的struct实例自身必须是可修改的。在这个场景下,被捕获【外部变量】的【可修改-引用】就是【闭包struct】的一个字段。[例程2]&, &mut, let ref,let ref mut [例程3]consuming”成员方法,从而“消费掉“实例变量自身 [例程5]!Copy trait值。!Trait语法,需要在程序首行前注入元属性:#![feature(negative_impls)]。Copy trait值的话,上述三类操作仅会取走【外部变量】值的【复本】,而不是触发变量的【所以权-转移】。[4] 在【闭包】内,对【外部变量】执行【可修改-借入】的判定标准是: [例程6]
let mut定义为可修改struct】实例被使用let mut绑定至可修改变量。然后,既然已经有【处理方式】决定【捕获方式】的设定,那你是否曾经质疑过move关键字开“后门”的必要性?在如下两个场景里,我们还真需要move强制指定【闭包】对【外部变量】的【捕获方式】。
被跨线程执行的【闭包】。例如,
在这个场景下,所有的【外部变量】都必须从A线程全量搬移到B线程(变量的【所有权】也就同时被转移了),以避免多线程数据竞争。
A线程定义一个【闭包】B线程执行。被高阶函数返回的【闭包】[例程7] 在这个场景下,【闭包】必须把它所依赖的【外部变量】一起转移走,无论在【闭包】业务代码里是仅只【引用】借入变量,还是“消费掉”变量【所有权】。
最后,我推荐对【闭包】代码解读的思维步骤如下:
先看【闭包】定义是否有move关键字前缀。
struct】实例的生命周期结束,我们也不能对其【外部变量】做任何的操作了。再看【闭包struct】实例是否被let mut绑定给 可修改变量。
struct】实例的生命周期内,我们不能对其【外部变量】做任何的操作了。接着,精读【闭包】业务代码。分析【闭包】是否对【外部变量】做了任何的【所有权-转移】操作。
struct】实例的生命周期结束,我们也不能对其【外部变量】做任何的操作了。若上面三个条件均不成立,那么
struct】实例的生命周期内,【外部变量】可读(只读-借入)struct】实例的生命周期结束后,我们便可恢复对【外部变量】的完全访问能力。