How to resolve creates a temporary variable which is freed while still in use?

I am trying to implement a Debug for my custom List<T> using a while loop but stuck at taking a reference of a pattern matched RefCell.

use std::rc::Rc;
use std::cell::RefCell;

type Link<T> = Option<Rc<RefCell<Node<T>>>>;
struct Node<T> {val: T, next: Link<T>}
struct List<T> {head: Link<T>, tail: Link<T>, len: usize}

use std::fmt;
impl<T: fmt::Debug> fmt::Debug for List<T> {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    let mut temp = &self.head;
    while let Some(r) = temp {
      write!(f, "{:?} -> ", r.borrow().val);
      temp = &r.borrow().next; // ERROR
      // temp = unsafe {& (*r.as_ptr()).next };
    }
    write!(f, "[]")
  }
}

Is there an Elegant, Idiomatic & Safe Rust that can get around this problem?
I don't want to implement Iterator for my list.

1 Like

You need to clone the Rc.

impl<T: fmt::Debug> fmt::Debug for List<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut temp = self.head.clone();
        while let Some(r) = temp {
            write!(f, "{:?} -> ", r.borrow().val);
            temp = r.borrow().next.clone();
        }
        write!(f, "[]")
    }
}

playground

The reason for this is that borrow() returns a guard with a destructor, and you can only access references into the RefCell while that guard is still active. So without cloning an Rc, you would need to keep all the guards from each iteration around, but the loop destroys the previous guard when advancing to the next iteration.

An Rc clone lets you access the next node without going through the guard, hence sidestepping the issue.

6 Likes

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.