调试打印导致字段类型为 std::rc::Rc 的结构的堆栈溢出

Ram*_*ana 5 rust

我正在遵循本书中的链表实现。和List结构Node是这样的 -

type Link<T> = Option<Rc<RefCell<Node<T>>>>;

#[derive(Debug)]
pub struct List<T> {
    head: Link<T>,
    tail: Link<T>,
}

#[derive(Debug)]
struct Node<T> {
    elem: T,
    next: Link<T>,
    prev: Link<T>,
}
Run Code Online (Sandbox Code Playgroud)

我有一个push_front像下面这样的方法 -

    pub fn push_front(&mut self, elem: T) {
        let new_node = Node::new(elem);
        let new_node = Rc::new(RefCell::new(new_node));
        let mut old_head = self.head.take();
        old_head.as_mut().map(|node| {
            node.borrow_mut().prev = Some(Rc::clone(&new_node));
        });
        new_node.borrow_mut().next = old_head.clone();
        self.head = Some(new_node);
        if self.tail.is_none() {
            self.tail = self.head.clone();
        }
    }
Run Code Online (Sandbox Code Playgroud)

该代码编译良好。List但是每当我在测试中放入调试打印时,我都会收到测试失败并显示消息thread 'tests::test_list_1' has overflowed its stack

    #[test]
    fn test_list_1() {
        let mut list = List::new();
        list.push_front(1);
        list.push_front(2);
        list.push_front(3);
        println!("{:?}", list);
        // assert!(false);
    }
Run Code Online (Sandbox Code Playgroud)

如果我注释掉该println!行,则测试通过。所以基本上调试打印list导致了这里的堆栈溢出。我无法理解到底为什么。

完整代码的Playground 链接。

我已经对代码进行了实验,以明确下面的行是否导致了问题。

println!("{:?}", list);
Run Code Online (Sandbox Code Playgroud)

所以我的猜测是,既然list有一个类型std::rc::Rc并且println!宏需要该值的引用,那么它会以某种方式在某处创建一个循环。但我无法具体确定问题所在。

Cha*_*man 6

派生impl Debug for Node打印 和prevnextprev将尝试打印其下一个节点(即当前节点)并将next尝试打印其prev(同上),因此这是无限递归。

您需要Debug手动实现:

impl<T: Debug> std::fmt::Debug for Node<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Node")
            .field("elem", &self.elem)
            .field("next", &self.next)
            .finish()
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您不想打印,也可以手动 impl Debugfor 。Listtail