为什么在 Rust 中移动闭包不能移动引用变量的所有权?

Why move closure in rust can't move the ownership of a referenced variable?

示例如下

fn call_with_f<F>(f:F) where F: FnOnce(){
    f();
}
struct Vec2{
    x:i32,
    y:i32
}
impl Vec2{
    fn new(x:i32, y:i32) -> Self{
        Self{
            x,
            y
        }
    }
    fn x(&self) -> &i32{
        &self.x
    }
}
fn main() {
    let v = Vec2::new(1,2);
    let rx = v.x();
    call_with_f(move||{
        println!("{}", v.x());
        println!("{}", rx);
    });
}

编译器给出

error[E0505]: cannot move out of `v` because it is borrowed
  --> src\main.rs:88:14
   |
87 |     let rx = v.x();
   |              - borrow of `v` occurs here
88 |     call_with_f(move||{
   |                 ^^^^^^ move out of `v` occurs here
89 |         println!("{}", v.x());
   |                        - move occurs due to use in closure
90 |         println!("{}", rx);
   |                        -- borrow later captured here by closure

我知道编译器的抱怨,但这种情况有时是必要的。在一个非常复杂的
在这种情况下,在进入闭包之前需要完成大量工作,作为中间变量的引用可以简化准备工作。 vrv 一开始的生命周期是一样的,根据 move 闭包的语义,它们移动后的生命周期也是一样的。为什么?

您不能移动借来的值。期间.

此外,这样的闭包不能(安全地)存在:它需要存储拥有的值和对它(的一部分)的引用,即它是 . See .

根据您的用例,可能有多种解决方案,从最好到最差排序:

  • 在闭包内创建引用。
  • 不要移动拥有的值。人们提出您的问题的常见原因之一是因为他们需要线程的 'static 闭包。如果是这种情况,您可能会发现 scoped threads 有帮助。
  • 使用诸如 owning_ref (unsound!) or ourboros(没有已知的音孔 IIRC)之类的板条箱来创建 self-referential 闭包。您可能需要手动对闭包进行脱糖(至少是部分脱糖)。
  • 使用 unsafe 代码创建自引用闭包。 警告:除非您真的知道自己在做什么,否则不要这样做。