在闭包上移动是复制引用“指针”还是引用的实际对象?

Elo*_*off 2 rust

如果不添加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`中指定值的静态生命周期,因此回调可以借用,但我认为它不是重复的。

use*_*198 6

move导致任何捕获变量的值被移动,而如果move未指定,并且闭包不消耗该变量,则闭包将尝试引用它。尽管变量是通过引用捕获的,但在闭包中,名称仍然像原始变量一样。

这里混淆的关键点来自于事实foo有 type &mut Foo, not Foo,它们是不同的类型。

所以在这种情况下,没有movea 的引用foo是用 type 创建的&'a mut &'static mut Foo,其中'a是方法foo内的生命周期main。这会导致错误,因为它限制了封闭件的寿命到小于'static所要求的do_something

  • @Eloff如果您熟悉其他语言,您可能习惯于将“引用”视为与“对象”不同,并且在作用于引用的操作与作用于对象的操作之间存在二分法。Rust 中没有这样的二分法:引用只是碰巧是引用类型的常规对象。因此,使用“foo”的“move”闭包将始终移动“foo”,无论它是否是引用。 (2认同)

归档时间:

查看次数:

97 次

最近记录:

5 年,3 月 前