RefCell::borrow 是否移动内容?

Does RefCell::borrow move the contents?

我有一个链表类型的结构,使用 Option、Rc 和 RefCell。

我想为它实现 fmt::Debug,但是 运行 进入可爱的 "cannot move out of borrowed content" 错误。

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() {}

理想情况下,调试输出能够显示 .next 和 .previous 节点的 ID。但是 Rust 不允许访问它们。尝试 .borrow() RefCell 的内容导致错误,但我不明白为什么。

在这里玩一下:http://is.gd/Sah7sT

Does RefCell::borrow() move the contents?

没有。叫它借来让它移动是相当卑鄙的! ^_^

问题是您正试图将 id 移出您借用的结构。这是一步,因为 String 不是 Copy:

n.borrow().nodeid.id

相反,使用 clone 保留当前字符串,return 一个全新的字符串:

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

为了扩展@Shepmaster 的答案(这是绝对正确的),在这种情况下,您可以通过将子节点的 ID 直接写入格式化程序来避免复制字符串。

我选择使用新类型来避免重复:

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"),
        }
    }
}