G.ASY.03 在跨 await 调用中,需要对其持有 RefCell 的引用进行处理

【级别】 建议

【描述】

使用 RefCell 的独占(可变)借用会导致 Panic。因为 RefCell 是运行时检查独占的可变访问,如果跨 await 持有一个可变引用则可能会因为共享的可变引用而引起 Panic。

这种共享可变在编译期是无法被检查出来的。

【反例】


#![allow(unused)]
#![warn(clippy::await_holding_refcell_ref)] 

fn main() {
use std::cell::RefCell;

async fn foo(x: &RefCell<u32>) {
  let mut y = x.borrow_mut();
  *y += 1;
  baz().await; // 不符合
}
}

【正例】


#![allow(unused)]
#![warn(clippy::await_holding_refcell_ref)] 

fn main() {
use std::cell::RefCell;

async fn foo(x: &RefCell<u32>) {
  {
    let mut y = x.borrow_mut();
    *y += 1;
  }
  baz().await; // 符合
}
}

【例外】

await 持有 RefCell 的可变借用,但是当前场景确信永远不会 Panic,则可以使用。

用例来源:wasm-streams


#![allow(unused)]
fn main() {
pub fn pull(&mut self, controller: sys::ReadableByteStreamController) -> Promise {
  let inner = self.inner.clone();
  let fut = async move {
    // 这个可变借用永远不会恐慌,因为 ReadableStream 对底层源的每个操作总是有序的。
    let mut inner = inner.try_borrow_mut().unwrap_throw();
    inner.pull(controller).await
  };
  // ...
}
}

【Lint 检测】

lint nameClippy 可检测Rustc 可检测Lint Grouplevel
await_holding_refcell_refyesnopedanticallow