在阅读Rust书的最后一章时,我不禁注意到move在封闭中没有使用它:
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
// move not used here
thread::spawn(|| {
handle_connection(stream);
});
}
}
Run Code Online (Sandbox Code Playgroud)
这是函数签名handle_connection:
fn handle_connection(mut stream: TcpStream) {}
Run Code Online (Sandbox Code Playgroud)
为什么不在move这里使用?什么会导致move从接线盒中必需的?
Rust可以判断闭包何时以需要移动的方式使用环境中的值.就像调用一个按值获取参数的函数(你的handle_connection情况):
let s = String::from("hi");
let c = || drop(s); // <-- `drop()` takes its argument by value
// Thus, the compiler knows `c` is a move closure
Run Code Online (Sandbox Code Playgroud)
或者,如果闭包按值返回对象:
let s = String::from("hi");
let c = || s; // <-- `s` is returned (FnOnce() -> String)
// Thus, the compiler knows `c` is a move closure
Run Code Online (Sandbox Code Playgroud)
通常,您不必注释move关键字以明确告诉编译器.
但是,如果闭包仅通过引用使用环境中的值,则编译器假定不必将该变量移动到闭包中.但它可能仍然需要另一个原因:生命.例:
fn get_printer(s: String) -> Box<Fn()> {
Box::new(|| println!("{}", s))
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器只看到s通过引用以只读方式使用(println不使用其参数).因此编译器不会使闭包成为闭包.但是这会导致生命周期错误,因为s现在生活在堆栈框架中,get_printer并且封闭框架的封闭寿命更长.因此,在这种情况下,您必须强制编译器通过添加move以下内容将环境移动到闭包中:
fn get_printer(s: String) -> Box<Fn()> {
Box::new(move || println!("{}", s))
}
Run Code Online (Sandbox Code Playgroud)