How to travel by &mut Option<Rc<RefCell<ListNode>>>

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

You can get your example to compile like this:

#![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;
}

Playground.

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).

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.