尝试从封装在 RefCell 中的结构中借用 2 个字段时出错 [英] Error while trying to borrow 2 fields from a struct wrapped in RefCell

查看:39
本文介绍了尝试从封装在 RefCell 中的结构中借用 2 个字段时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个结构体,其中包含数据和最终用于写入数据的编写器.该结构包含在 RefCell 中.这是一个小复制:

I have a struct which contains both data and a writer which will eventually be used to write the data. The struct is wrapped in a RefCell. Here's a small reproduction:

use std::cell::RefCell;
use std::io::Write;

struct Data {
    string: String,
}

struct S {
    data: Data,
    writer: Vec<u8>,
}

fn write(s: RefCell<S>) {
    let mut mut_s = s.borrow_mut();
    let str = &mut_s.data.string;
    mut_s.writer.write(str.as_bytes());
}

编译器生气了:

error[E0502]: cannot borrow `mut_s` as mutable because it is also borrowed as immutable
  --> src\main.rs:16:5
   |
15 |     let str = &mut_s.data.string;
   |                ----- immutable borrow occurs here
16 |     mut_s.writer.write(str.as_bytes());
   |     ^^^^^ mutable borrow occurs here
17 | }
   | - immutable borrow ends here

我应该使用不同的 API 吗?

Is there a different API I should use?

推荐答案

您可以手动调用 DerefMut 然后保存结果引用:

You can manually invoke DerefMut and then save the resulting reference:

fn write(s: RefCell<S>) {
    let mut mut_s = s.borrow_mut();
    let mut tmp = &mut *mut_s; // Here
    let str = &tmp.data.string;
    tmp.writer.write(str.as_bytes());
}

或在一行中:

fn write(s: RefCell<S>) {
    let mut_s = &mut *s.borrow_mut(); // Here
    let str = &mut_s.data.string;
    mut_s.writer.write(str.as_bytes());
}


问题在于 borrow_mut 不直接返回你的结构——它返回一个 RefMut.通常,这是透明的,因为该结构实现了 DerefDerefMut,因此对其调用的任何方法都会传递给基础类型.伪扩展代码如下所示:


The problem is that borrow_mut doesn't return your struct directly — it returns a RefMut. Normally, this is transparent as this struct implements Deref and DerefMut, so any methods called on it are passed to the underlying type. The pseudo-expanded code looks something like this:

use std::cell::RefMut;
use std::ops::{Deref, DerefMut};

fn write(s: RefCell<S>) {
    let mut mut_s: RefMut<S> = s.borrow_mut();
    let str = &Deref::deref(&mut_s).data.string;
    DerefMut::deref_mut(&mut mut_s).writer.write(str.as_bytes());
}

Rust 不跟踪跨函数调用的字段级借用(即使对于 Deref::derefDerefMut::deref_mut).这会导致您的错误,因为在从之前的 Deref::deref 借用期间,需要调用 deref_mut 方法.

Rust doesn't track field-level borrows across function calls (even for Deref::deref or DerefMut::deref_mut). This causes your error, as the deref_mut method would need to be called during the outstanding borrow from the previous Deref::deref.

具有显式借用的扩展版本如下所示,只需调用一次 Deref::deref_mut:

The expanded version with the explicit borrow looks like this, with a single call to Deref::deref_mut:

use std::cell::RefMut;
use std::ops::DerefMut;

fn write(s: RefCell<S>) {
    let mut mut_s: RefMut<S> = s.borrow_mut();
    let tmp: &mut S = DerefMut::deref_mut(&mut mut_s);
    let str = &tmp.data.string;
    tmp.writer.write(str.as_bytes());
}

然后编译器可以跟踪从该临时值中借用的两个对象是不相交的.

The compiler can then track that the two borrows from that temporary value are disjoint.

注意这个问题不是RefCell独有的!任何实现 DerefMut 的类型都可以遇到同样的问题.以下是标准库中的一些内容:

Note that this problem isn't unique to RefCell! Any type that implements DerefMut can experience the same problem. Here's some from the standard library:

  • Box
  • MutexGuard (from Mutex)
  • PeekMut (from BinaryHeap)
  • RwLockWriteGuard (from RwLock)
  • String
  • Vec
  • Pin

这篇关于尝试从封装在 RefCell 中的结构中借用 2 个字段时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆