首页 文章

尝试从RefCell中包含的结构中借用2个字段时出错

提问于
浏览
6

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

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吗?

1 回答

  • 10

    您可以手动调用 DerefMut ,然后保存生成的引用:

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

    或者在一行中:

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

    问题是borrow_mut不直接返回你的结构 - 它返回一个RefMut . 通常,这是透明的,因为此结构实现DerefDerefMut,因此调用它的任何方法都将传递给基础类型 . pseduo扩展代码看起来像这样:

    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 方法 .

    具有显式借用的扩展版本看起来像这样,只需调用 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());
    }
    

    然后,编译器可以跟踪该临时值的两个借位是不相交的 .


    注意这个问题 isn't uniqueRefCell !任何实现DerefMut的类型都可能遇到同样的问题 . 以下是标准库中的一些内容:

相关问题