如何要求闭包在其范围结束时归还借用?

问题描述 投票:0回答:1

考虑以下函数体:


    fn update_acc(&mut self, acc_rub: &Vector3<f32>, _t: u64) -> () {
        let acc = Self::rub_to_frd(acc_rub);

        if acc.norm() < 1.0 {
            return (); // almost in free fall, or acc disabled, do not correct
        }

        let delta_opt = || -> Option<UnitQuaternion<f32>> {
            let uncorrected = self.attitude.inverse().transform_vector(&Self::UP_FRD);
            let delta_opt = UnitQuaternion::rotation_between(&acc, &uncorrected);

            delta_opt
        };

        let dd = delta_opt();
        match dd {
            Some(delta) => {
                self.inconsistency = self.inconsistency * Self::INCONSISTENCY_DECAY + delta.angle();

                match UnitQuaternion::try_slerp(
                    &UnitQuaternion::identity(),
                    &delta,
                    Self::BASE_GRAV_RATIO,
                    0.01,
                ) {
                    Some(correction) => {
                        let new_attitude = self.attitude * correction;
                        self.attitude = new_attitude;

                        {
                            // TODO: verification code, clean up
                            let residual = delta_opt().unwrap().angle().abs();
                            if (residual >= 0.01) {
                                println!("!!!!!!!!!! residual: {} !!!!!!!!!!", residual);
                            }
                        }
                    }
                    None => {
                        // TODO: opposite direction, don't know how to correct
                    }
                };
            }
            None => {
                // no error no update
            }
        }
    }

编译时出现以下错误:

error[E0506]: cannot assign to `self.attitude` because it is borrowed
   --> src/naive_cf.rs:160:25
    |
140 |         let delta_opt = || -> Option<UnitQuaternion<f32>> {
    |                         --------------------------------- `self.attitude` is borrowed here
141 |             let uncorrected = self.attitude.inverse().transform_vector(&Self::UP_FRD);
    |                               ------------- borrow occurs due to use in closure
...
160 |                         self.attitude = new_attitude;
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.attitude` is assigned to here but it was already borrowed
...
164 |                             let residual = delta_opt().unwrap().angle().abs();
    |                                            --------- borrow later used here

这个错误很难重现,如果我将调用内联到闭包

delta_opt
,错误就会消失。如果我尝试在一个稍微简单的函数中重现它,并且在闭包中也使用
self.attitude
,错误也会消失:


    fn dummy(&mut self) -> () {

        let delta_opt = || -> (Option<f32>) {
            let a = self.attitude.inverse();
            Some(a.i)
        };
        match delta_opt() {
            Some(v) => {
                self.attitude = UnitQuaternion::identity();
            }
            None => {}
        }
    }

我有3个问题:

  • 为什么关闭
    dummy
    并没有篡改
    self.attitude
    的借用状态?有什么区别?
  • 如何修改闭包
    delta_opt
    ,以便在对闭包的调用返回时返回
    self.attitude
    的借用?
  • 如何重写闭包
    delta_opt
    以使其成为内联扩展? (即编译器可以将其调用扩展到其代码实现中)
rust closures borrow-checker inline-functions
1个回答
0
投票

我认为会发生以下情况:

它适用于您的虚拟示例,因为在虚拟示例中您只使用了一次闭包。编译器足够聪明,能够意识到这一点,因此它会尽早删除闭包,以便在要释放的闭包中发生借用到

self.attitude

在您的完整示例中,您在其中一个匹配臂中对关闭进行了第二次调用。因此,闭包不能提前删除,这意味着对

self.attitude

 的借用保持活动状态,并且分配给它是一个错误。

© www.soinside.com 2019 - 2024. All rights reserved.