0
votes

I have a linked-list sort of struct, using Option, Rc, and RefCell.

I'd like to implement fmt::Debug for it, but have run into the lovely "cannot move out of borrowed content" error.

use std::fmt;
use std::rc::{Rc, Weak};
use std::cell::RefCell;

#[derive(Clone, Debug, Ord, Eq, PartialOrd, PartialEq)]
struct NodeId {id: String}

impl NodeId {
    pub fn new(s: &str) -> NodeId { NodeId{id: s.to_string()}}
}

struct NodeInfo {
    nodeid: NodeId,
    prev: Option<Rc<RefCell<NodeInfo>>>,
    next: Option<Rc<RefCell<NodeInfo>>>,
}

impl fmt::Debug for NodeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NodeInfo( {} {} {} )", self.nodeid.id,
        match self.prev { None => "none".to_string(), Some(ref n) => n.borrow().nodeid.id},
        match self.next { None => "none".to_string(), Some(ref n) => "some".to_string()},
        )
    }
}

fn main() {}

Ideally the debug output would be able to show me the ids of the .next and .previous nodes. But Rust is not allowing access to them. The attempt to .borrow() the content of the RefCell causes the error, but I cannot understand why.

Play with it here: http://is.gd/Sah7sT

2

2 Answers

3
votes

Does RefCell::borrow() move the contents?

No. Calling it borrow and having it move would be pretty underhanded! ^_^

The problem is that you are trying to move the id out of your borrowed struct. This is a move because String isn't Copy:

n.borrow().nodeid.id

Instead, use clone to leave the current string where it is, and return a brand-new one:

n.borrow().nodeid.id.clone()
3
votes

To expand on @Shepmaster's answer (which is absolutely correct), you can avoid having to copy the string in this case, by writing the id of the child nodes directly to the formatter.

I've chosen to use a newtype to avoid repetition:

impl fmt::Debug for NodeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NodeInfo( {} {:?} {:?} )", self.nodeid.id, ChildNode(&self.prev), ChildNode(&self.next))
    }
}

struct ChildNode<'a>(&'a Option<Rc<RefCell<NodeInfo>>>);

impl<'a> fmt::Debug for ChildNode<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self.0 {
            Some(ref n) => write!(f, "{}", n.borrow().nodeid.id),
            None        => write!(f, "None"),
        }
    }
}