结论:闭包按"使用方式"自动推断捕获模式:只读则捕获 &T(实现 Fn)、需要修改则捕获 &mut T(实现 FnMut)、需要消费或移出捕获值则按值捕获(只实现 FnOnce);加 move 关键字则强制按值(所有权)捕获所有用到的环境变量。

展开:三个 trait 是包含关系:每个闭包至少实现 FnOnce,不消耗捕获的还能实现 FnMut,连修改都不做的实现 Fn;函数参数按需声明即可。move 常用于两处:①把捕获数据的所有权送进新线程——thread::spawn 要求闭包满足 'static,不能借用栈上数据;②让闭包返回值不受环境借用约束。易错点:moveCopy 类型仍是复制而非移动;edition 2021 起闭包按"字段级"精确捕获(disjoint capture),不再总是捕获整个变量;闭包内只调用 x.clone() 时通常不需要 move。追问方向:为什么 thread::spawn 闭包常要 move?线程可能比当前栈帧活得久,借用栈数据会悬垂。

let name = String::from("ohmy");
let handle = std::thread::spawn(move || {
    println!("{name}"); // move:name 的所有权进入闭包
});
handle.join().unwrap();
// println!("{name}"); // 错误:name 已被移动