2016-02-25 5 views
0

У меня есть структура с двумя указателями C и одной Rust HashMap.Как я могу обойти проблему RefCell?

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 и p2 и некоторые 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); 
    } 
} 

(Playpen)

Как я могу обойти эту проблему?

+0

Есть ли причина, по которой вы не можете просто скопировать 'p1' и' p2' из 'my_struct'? В конце концов, это просто странные типизированные числа ... –

+0

Тогда вам придется переместить 'RefCell' в поле' hm', а затем 'p1' и' p2' больше не могут быть изменены. –

+0

BTW, ящик вокруг HashMap почти наверняка бессмыслен, вы можете просто сохранить HashMap напрямую. – delnan

ответ

4

Ваша проблема заключается в том, что вызов 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 ваш объект тоже.

+0

Вызов 'loan()' дважды не является проблемой, но это действительно работает. – dragostis

+0

фиксированный ответ. Вы, конечно, правы –

2

Ручки ручки заимствуют разные поля в одном struct, но для того, чтобы увидеть это, все поля должны быть заимствованы в одном и том же лексическом элементе (например, одна функция).

Таким образом, вы, по крайней мере, два пути для производства:

  • реорганизовать свой заимствует, так что вы выбираете struct друг от друга в одном месте, получать ссылки на каждый из областей
  • реорганизовать свой заимствует так, что первый заканчивается до того, как второй один нужен

в зависимости от ситуации, какое решение вы выбираете, будет отличаться:

  • выбирая struct друг от друга означает возможность передать ссылку на поле вместо всей struct
  • заканчивающегося Заимствование первый означает возможность копировать данные заимствованных полей вместо того, чтобы ссылочный
Смежные вопросы