如果不添加move到闭包中,此代码不会编译。它产生错误:
error[E0373]: closure may outlive the current function, but it borrows `foo`, which is owned by the current function
--> src/main.rs:26:18
|
26 | do_something(|| {
| ^^ may outlive borrowed value `foo`
27 | foo.bar += 1;
| --- `foo` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:26:5
|
26 | / do_something(|| {
27 | | foo.bar += 1;
28 | | println!("{}", foo.bar);
29 | | });
| |______^
help: to force the closure to take ownership of `foo` (and any other referenced variables), use the `move` keyword
|
26 | do_something(move || {
| ^^^^^^^
Run Code Online (Sandbox Code Playgroud)
这个错误令人困惑,因为它似乎意味着比 'static 需要更长的生命周期,好像任何东西都可以比 'static 长。这foo是'static对结构的引用。如果我添加move到闭包中,它不会将引用的结构本身移动到闭包中吗?或者它只是复制引用(指针位)?在我看来,它只是在移动参考,而不是Foo它本身。我对移动闭包如何与引用相关的理解非常模糊。
struct Foo {
bar: i32,
}
impl Drop for Foo {
fn drop(&mut self) {
panic!("dropping Foo, should never happen");
}
}
pub fn do_something<F, T>(mut f: F)
where
F: FnMut() -> T + 'static,
T: 'static,
{
// "spawn" 3 threads
f();
f();
f();
}
fn main() {
let foo = Box::leak::<'static>(Box::new(Foo { bar: 0 }));
let raw_ptr: *const Foo = foo;
do_something(move || {
foo.bar += 1;
println!("{}", foo.bar);
});
println!("{}", unsafe { (*raw_ptr).bar });
}
Run Code Online (Sandbox Code Playgroud)
这个问题类似于在`main`中指定值的静态生命周期,因此回调可以借用,但我认为它不是重复的。
move导致任何捕获变量的值被移动,而如果move未指定,并且闭包不消耗该变量,则闭包将尝试引用它。尽管变量是通过引用捕获的,但在闭包中,名称仍然像原始变量一样。
这里混淆的关键点来自于事实foo有 type &mut Foo, not Foo,它们是不同的类型。
所以在这种情况下,没有movea 的引用foo是用 type 创建的&'a mut &'static mut Foo,其中'a是方法foo内的生命周期main。这会导致错误,因为它限制了封闭件的寿命到小于'static所要求的do_something。
| 归档时间: |
|
| 查看次数: |
97 次 |
| 最近记录: |