Rust 2021版闭包捕获规则疑问:可变引用i是否存在隐式move?
核心背景:Rust 2021 闭包捕获规则优化
你观察到的版本差异、几个代码片段的编译表现,核心是Rust 2021 引入的闭包精准捕获特性:闭包会根据内部实际操作自动选择最小粒度的捕获内容,而非直接捕获整个变量。
1. 不存在对i的隐式move
你给出的闭包仅执行*i的读操作,只需要持有&i32就能完成逻辑,因此编译器不会捕获原来的&mut i32变量i,而是自动对i做不可加重借用,得到一个生命周期和输入参数i绑定的&i32,闭包实际捕获的是这个全新的不可变引用,完全没有涉及原变量i的所有权转移。
注:
&mut没有实现Copy trait的规则确实成立,但本场景下根本没有发生对原i的move操作,自然不会出现「变量已移动」的借用错误。
2. 第二段代码可正常编译的原因
闭包捕获的是*i的不可变引用,而println!("{:?}", i)执行的也是对*i的不可变借用,Rust借用规则允许同一时间存在多个不可变借用,二者不存在冲突,因此可以正常编译。
3. 第三段代码编译失败的验证逻辑
第三段代码的返回值为impl Fn() -> i32,没有标注生命周期,根据Rust的impl Trait生命周期省略规则,无标注的impl Trait返回值默认要求满足'static生命周期约束。
如果闭包是复制了i指向的值,那么闭包本身没有任何外部生命周期依赖,完全符合'static要求,应当可以编译。但实际编译失败,恰恰验证了闭包捕获的是和输入参数i生命周期绑定的不可变引用,无法满足'static约束,和你的判断一致。
4. Rust 2018 编译失败的原因
Rust 2018的闭包捕获规则更保守,只要闭包内用到了变量i,就会直接捕获整个&mut i32本身。而捕获了&mut T的闭包最多只能实现FnMut trait(调用需要&mut self),无法满足返回值声明的Fn trait约束,因此编译失败。
内容的提问来源于stack exchange,提问作者vikram2784

