考虑以下函数体:
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
以使其成为内联扩展? (即编译器可以将其调用扩展到其代码实现中)我认为会发生以下情况:
它适用于您的虚拟示例,因为在虚拟示例中您只使用了一次闭包。编译器足够聪明,能够意识到这一点,因此它会尽早删除闭包,以便在要释放的闭包中发生借用到
self.attitude
。
在您的完整示例中,您在其中一个匹配臂中对关闭进行了第二次调用。因此,闭包不能提前删除,这意味着对 self.attitude
的借用保持活动状态,并且分配给它是一个错误。