简体   繁体   English

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

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

Here's the example这是示例

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);
    });
}

The compiler gives编译器给出

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

I know the complaint of compiler, but this case is necessary sometime.我知道编译器的抱怨,但这种情况有时是必要的。 In a very complicated在一个非常复杂的
circumstance, a bunch of work need to be done before given into the closure, a reference as an intermediate varible could simplify the preparation.在这种情况下,在给闭包之前需要做很多工作,作为中间变量的引用可以简化准备工作。 v and rv have same lifetime at the beginning, they also remain the same lifetime after moved according to the semantics of the move closure. vrv在开始时具有相同的生命周期,根据移动闭包的语义,它们在移动后也保持相同的生命周期。 Why?为什么?

You cannot move a borrowed value.您不能移动借入的值。 Period.时期。

Moreover, such closure cannot exist (safely): it needs to store both the owned value and a reference to (part of) it, ie it is self-referential .此外,这样的闭包不能(安全地)存在:它需要存储拥有的值和对它(部分)的引用,即它是自引用的 See Lifetime of references in closures .请参阅闭包中引用的生命周期

Depending on your use case, there may be various solutions, ordered from the best to the worst:根据您的用例,可能有各种解决方案,从最好到最差排序:

  • Create the reference inside the closure.在闭包内创建引用。
  • Don't move the owned value.不要移动拥有的价值。 One of the common reasons people have your question is because they need a 'static closure for threads.人们提出问题的常见原因之一是因为他们需要线程的'static闭包”。 If this is the case, you may find scoped threads helpful.如果是这种情况,您可能会发现作用域线程很有帮助。
  • Use a crate such as owning_ref (unsound!) or ourboros (no known sound holes IIRC) to create the self-referential closure.使用诸如owning_ref (unsound!) 或ourboros (no known sound hole IIRC) 之类的 crate 来创建自引用闭包。 You may need to desugar the closure manually (partially, at least).您可能需要手动(至少部分地)对关闭进行脱糖。
  • Use unsafe code for creating the self referential closure.使用unsafe的代码来创建自引用闭包。 WARNING: Do Not Do That Unless You Really Know What You're Doing.警告:除非您真的知道自己在做什么,否则不要这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM