在阅读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);
});
}
}
这是handle_connection
的功能签名:
fn handle_connection(mut stream: TcpStream) {}
为什么这里不使用move
?是什么导致封闭中需要move
?
答案 0 :(得分:8)
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
或者如果闭包通过值返回对象:
let s = String::from("hi");
let c = || s; // <-- `s` is returned (FnOnce() -> String)
// Thus, the compiler knows `c` is a move closure
因此,通常不必注释move
关键字即可明确告知编译器。
但是,如果闭包仅通过引用使用环境中的值,则编译器会认为不需要将该变量移至闭包中。但是出于另一个原因,可能仍然有必要:终身。示例:
fn get_printer(s: String) -> Box<Fn()> {
Box::new(|| println!("{}", s))
}
在这种情况下,编译器只会看到s
通过引用以只读方式使用(println
不使用其参数)。因此,编译器不会使闭包成为移动闭包。但这会导致生命周期错误,因为s
现在位于get_printer
的堆栈框架中,而闭包的寿命超过了该堆栈框架。因此,在这种情况下,您必须通过添加move
来强制编译器将环境移至闭包中:
fn get_printer(s: String) -> Box<Fn()> {
Box::new(move || println!("{}", s))
}