I'm trying to create a mutable structure B
which stores instances of other structure A
that hold references to B
. I want an implementation such that any mutation done to the original B
propagates to the references held in the A
s.
However, during the mutation, I have to check a field from the B
instance wrapped in A
instance, thus breaking the "one mutable xor many immutable" rule. I need to borrow immutably while borrowed mutably, but the immutable borrow is internal to the mutating function and does not outlive its scope.
use std::cell::RefCell;
use std::rc::{Rc, Weak};
#[derive(Debug)]
struct A {
t: Weak<RefCell<B>>,
}
#[derive(Debug)]
struct B {
a: usize,
item: Option<A>,
}
impl B {
pub fn mutate(&mut self, item: A) {
{
let t = item.t.upgrade().unwrap();
// This check has to be done.
//
assert![t.borrow().a == self.a, "not equal"];
// ~~~~~~~~~~ panics on this borrow
}
//
// The immutable borrow should end here.
self.item = Some(item);
self.a += 1;
}
}
fn main() {
let b = B { item: None, a: 0 };
let bc = Rc::new(RefCell::new(b));
let f = A {
t: Rc::downgrade(&bc),
};
bc.borrow_mut().mutate(f);
println!["{:?}", bc.borrow().item.as_ref().unwrap().t.upgrade()];
}
It panics with:
thread 'main' panicked at 'already mutably borrowed: BorrowError'
Can these requirements be met using only Rc<RefCell<B>>
? If not, do I have to sink into unsafe
code?
The docs for RefCell::borrow
say:
Panics
Panics if the value is currently mutably borrowed. For a non-panicking variant, use
try_borrow
.
Using try_borrow
with the knowledge that any existing borrow must be self
(and thus is equal) allows your code to compile:
let eq = t.try_borrow().map_or(true, |v| v.a == self.a);
assert![eq, "not equal"];
See also: