我如何解决RefCell问题?

时间:2016-02-25 11:28:34

标签: rust borrow-checker

我有一个包含两个C指针和一个Rust HashMap的结构。

struct MyStruct {
    p1: *mut ...,
    p2: *mut ...,
    hm: Box<HashMap<...>>
}

我的结构被处理为Rc<RefCell<MyStruct>>并且我有一个被调用的C函数:

c_call(my_struct.borrow().p1, my_struct.borrow().p2);

C有一个Rust回调函数在执行c_call期间被调用,需要my_struct.borrow_mut(),但my_struct已经借用c_call需要p1 p2 }和RefCell<T> already borrowed,所以我得到c_call

问题在于p1无法更改,并且需要对p2borrow_mut以及my_struct use std::cell::RefCell; use std::collections::HashMap; use std::mem::uninitialized; use std::os::raw::c_void; use std::rc::Rc; struct MyStruct { p1: *mut c_void, p2: *mut c_void, hm: Box<HashMap<String, String>> } // c_call can't mutate hm because my_struct is already borrowed // c_call can't be changed fn c_call(_p1: *mut c_void, _p2: *mut c_void, my_struct: Rc<RefCell<MyStruct>>) { my_struct.borrow_mut().hm.insert("hey".to_string(), "you".to_string()); } // call only receives Rc<RefCell<MyStruct>> and need to call c_call fn call(my_struct: Rc<RefCell<MyStruct>>) { c_call(my_struct.borrow().p1, my_struct.borrow().p2, my_struct.clone()); } fn main() { unsafe { let my_struct = MyStruct { p1: uninitialized::<*mut c_void>(), // irrelevant p2: uninitialized::<*mut c_void>(), hm: Box::new(HashMap::new()) }; let my_struct = Rc::new(RefCell::new(my_struct)); call(my_struct); } } 的{​​{1}}进行不可变的访问。

这是一个MCVE:

this.tcpClient = new TcpClient();
this.tcpClient.Connect(/*Enter address and port*/);

this.networkStream = this.tcpClient.GetStream();
this.streamReader = new StreamReader(this.networkStream);
this.streamWriter = new StreamWriter(this.networkStream);

Playpen

如何解决此问题?

2 个答案:

答案 0 :(得分:5)

您的问题是在borrow()调用的参数中调用c_call将借用该对象,直到调用结束。如果您将其更改为

let (p1, p2) = {
    let x = my_struct.borrow();
    (x.p1, x.p2)
};
c_call(p1, p2, my_struct.clone());

然后借用在c_call来电之前结束,因此c_call也可以borrow_mut您的对象。

答案 1 :(得分:2)

Rust处理借用单个struct的不同字段就好了,但是为了看到这一点,所有字段都必须借用相同的词汇项(例如,单个函数)。

因此,您至少有两种方法可以继续:

  • 重构您的借用,以便您在一个地方选择struct,获取对其每个字段的引用
  • 重构您的借用,以便第一个在需要第二个之前结束

根据您的具体情况,您选择的解决方案会有所不同:

  • 选择struct分开意味着能够将引用传递给字段而不是整个struct
  • 首先结束借入意味着能够复制借用字段的数据而不是保留引用