0

我有一个带有两个 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,需要 a my_struct.borrow_mut(),但my_struct已经借用了c_call哪个需要p1p2,所以我得到RefCell<T> already borrowed.

问题是c_call无法更改,它需要不可变访问p1p2一些borrow_mut.my_struct

这是一个 MCVE:

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);
    }
}

游戏围栏

我该如何解决这个问题?

4

2 回答 2

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

于 2016-02-25T12:43:07.467 回答
2

Rust 可以很好地处理借用单个字段的不同字段struct,但是为了看到这一点,必须在同一个词项中借用所有字段(例如,单个函数)。

因此,您至少有两种途径进行:

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

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

  • 选择struct分开意味着能够传递对字段的引用而不是整体struct
  • 首先结束借用意味着能够复制借用字段的数据而不是保留引用
于 2016-02-25T14:59:07.873 回答