I try to travel through a ListNode and ListNode2 used in some leetcode problems. For ListNode, I hold a &Option<Box<ListNode>> and I can travel to next without problem. For ListNode2, I hold a &Option<Rc<RefCell<ListNode>>> but fail to travel to next. I don't understand why.
My final goal is to travel by &mut Option<Rc<RefCell<ListNode>>>, thus I can modify it inplace, to avoid creating dummy head.
struct ListNode {
val: i32,
next: Option<Box<ListNode>>,
}
let x = Some(Box::new(ListNode { val: 0, next: None }));
let mut y = &x;
y = &y.as_ref().unwrap().next; // ok
let mut x = Some(Box::new(ListNode { val: 0, next: None }));
let mut y = &mut x;
y = &mut y.as_mut().unwrap().next; // ok
struct ListNode2 {
val: i32,
next: Option<Rc<RefCell<ListNode2>>>,
}
let x = Some(Rc::new(RefCell::new(ListNode2 { val: 0, next: None })));
let mut y = &x;
y = &y.as_ref().unwrap().as_ref().borrow().next; // not ok
let mut x = Some(Rc::new(RefCell::new(ListNode2 { val: 0, next: None })));
let mut y = &mut x;
y = &mut y.as_ref().unwrap().as_ref().borrow().next; // not ok
#![allow(unused_assignments)]
#![allow(dead_code)]
use std::cell::RefCell;
use std::rc::Rc;
struct ListNode {
val: i32,
next: Option<Box<ListNode>>,
}
struct ListNode2 {
val: i32,
next: Option<Rc<RefCell<ListNode2>>>,
}
fn main() {
let x = Some(Box::new(ListNode { val: 0, next: None }));
let mut y = &x;
y = &y.as_ref().unwrap().next; // ok
let mut x = Some(Box::new(ListNode { val: 0, next: None }));
let mut y = &mut x;
y = &mut y.as_mut().unwrap().next; // ok
let x = Some(Rc::new(RefCell::new(ListNode2 { val: 0, next: None })));
let mut y = &x;
let temp = &y.as_ref().unwrap().as_ref().borrow().next.clone();
y = temp;
let mut x = Some(Rc::new(RefCell::new(ListNode2 { val: 0, next: None })));
let mut y = &mut x;
let temp = &mut y.as_ref().unwrap().as_ref().borrow().next.clone();
y = temp;
}
We have to create a temporary let-binding that increases the ref-count of the Rc by cloning it. Then we can pass a reference to it around, though note that passing a &mut Rc<RefCell<T>> is probably not what you want, because you want to borrow the inner value (in your case ListNode2) as mutable through RefCell::borrow_mut, most likely. This is known as interior mutability and is a useful pattern for situations where mutable references are too restrictive and you need to mutate through a shared reference (the Rc in your case).