此处可能会使用不可变借用,当“guard”被删除并运行“RwLockWriteGuard”类型的“Drop”代码时

Immutable borrow might be used here, when `guard` is dropped and runs the `Drop` code for type `RwLockWriteGuard`

在相同范围内不可变地借用借用的可变引用后,我如何更改它的值?在我的例子中,不可变地借用的部分包含在 Arc<RwLock<T>>

我遇到问题的实际片段:

Event::RedrawRequested(_) => {
    let mut guard = app.write().unwrap();
    let guard = &mut *guard;

    // (...)

    app.camera_controller.as_mut().unwrap().update_camera(app.camera.as_mut().unwrap(), dt);
    dt = frame_start.elapsed();
}

我有一个关于我的问题的最小示例:

use std::{
    ops::Deref,
    sync::{Arc, RwLock},
};

struct Inner {
    inner_number: Option<f32>,
}

struct App {
    inner: Arc<RwLock<Inner>>,
    outer_number: Option<f32>,
}

impl App {
    fn new(inner_number: f32, outer_number: f32) -> Self {
        Self {
            inner: Arc::new(RwLock::new(Inner {
                inner_number: Some(inner_number),
            })),
            outer_number: Some(outer_number),
        }
    }
}

impl Deref for App {
    type Target = Arc<RwLock<Inner>>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

fn main() {
    let mut app = App::new(10.0, 20.0);

    {
        let mut guard = app.write().unwrap();
        let guard = &mut *guard;

        guard.inner_number = Some(guard.inner_number.unwrap() + 5.0);

        *(app.outer_number.as_mut().unwrap()) *= 2.0;
    }

    println!("{:?}", app.outer_number);
}

错误:

   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `app.outer_number` as mutable because it is also borrowed as immutable
  --> src/main.rs:42:11
   |
37 |         let mut guard = app.write().unwrap();
   |                         ----------- immutable borrow occurs here
...
42 |         *(app.outer_number.as_mut().unwrap()) *= 2.0;
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
43 |     }
   |     - immutable borrow might be used here, when `guard` is dropped and runs the `Drop` code for type `RwLockWriteGuard`

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error

操场:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=935e70d66af8343b19aea4a0f280a27a.

到目前为止,我发现有两种方法可以编译您的代码。

解决方案 #1:

fn main() {
    let mut app = App::new(10.0, 20.0);

    {
        {
            let mut guard = app.write().unwrap();
            let guard = &mut *guard;

            guard.inner_number = Some(guard.inner_number.unwrap() + 5.0);
            // Drop guard here, which will release the `app` borrow
        }

        *(app.outer_number.as_mut().unwrap()) *= 2.0;
    }

    println!("{:?}", app.outer_number);
}

这个之所以有效,是因为 guard*= 2.0 之前被丢弃了。 app 不能在 guard 期间可变地借用一次,在 *= 2.0 期间不可可变地借用一次。永远不能同时以可变方式和不可变方式借用对象。将整个 guard 部分包装在其自己的上下文中可确保 guard*= 2.0 部分之前发布。

解决方案 #2:

fn main() {
    let mut app = App::new(10.0, 20.0);

    {
        // Use app.inner.write instead of app.write
        let mut guard = app.inner.write().unwrap();
        let guard = &mut *guard;

        guard.inner_number = Some(guard.inner_number.unwrap() + 5.0);

        *(app.outer_number.as_mut().unwrap()) *= 2.0;
    }

    println!("{:?}", app.outer_number);
}

之所以有效,是因为 guard 实际上并没有将整个 app 作为参考,而只是 app.inner 成员。由于 *= 2.0 部分仅引用 app.outer_number,它不会抱怨,因为这两个部分实际上并没有借用同一个对象。