不使用 move
关键字的情况
- 所有权分析:
- 在这段代码
let closure = || println!("{}", s);
中,闭包closure
捕获了变量s
,但此时并没有转移s
的所有权。
- 闭包默认以借用的方式捕获外部变量。这里闭包捕获
s
为不可变借用,因为println!
只是读取s
的内容。
- 由于闭包只是借用
s
,所以在闭包之后,s
仍然可以被使用。例如,如果在闭包定义之后添加println!("{}", s);
,代码依然可以正常编译和运行,因为s
的所有权还在原来的作用域。
- 代码示例:
fn main() {
let s = String::from("hello");
let closure = || println!("{}", s);
closure();
println!("{}", s);
}
- 上述代码会依次打印
hello
两次,证明s
的所有权未转移,在闭包调用后仍然可以使用。
使用 move
关键字的情况
- 所有权分析:
- 当使用
move
关键字,即let closure = move || println!("{}", s);
时,闭包会获取s
的所有权。
move
关键字强制闭包获取它所捕获变量的所有权,而不是借用。这意味着变量s
的所有权从定义它的作用域转移到了闭包中。
- 一旦所有权转移到闭包,在闭包外部就不能再使用
s
。例如,如果在闭包定义之后添加println!("{}", s);
,代码将无法编译,会报错提示s
已被移动。
- 代码示例:
fn main() {
let s = String::from("hello");
let closure = move || println!("{}", s);
// println!("{}", s); // 这行代码会报错,因为s的所有权已被闭包move走
closure();
}
- 上述代码中,取消注释
println!("{}", s);
会导致编译错误,提示s
已被移动。而闭包closure
可以正常调用并打印hello
,因为它拥有了s
的所有权。