You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Common Lisp双向链表节点互引引发无限打印的原因与解决办法

Common Lisp双向链表打印无限循环问题解析与解决方法

问题原因

SBCL对defstruct定义的结构体,默认打印行为是递归遍历并打印所有槽位的值。当你让*original*的prev指向*new*,同时*new*的next指向*original*时,就形成了循环引用链:打印*original*时会输出它的prev(即*new*),打印*new*时又会输出它的next(即*original*),这个过程会无限重复,最终导致打印陷入死循环。

解决方法

方法1:启用循环引用打印标记(标准方法)

Common Lisp提供了全局变量*print-circle*,将其设为t后,打印系统会自动检测循环引用,用#n=(定义标记)和#n#(引用标记)来表示循环结构,不会无限递归。

示例代码:

(setf *print-circle* t)
(print *original*)

输出示例:

#1=#S(NODE :DATA "world" :NEXT NIL :PREV #2=#S(NODE :DATA "hello" :NEXT #1# :PREV NIL))

这种方式不需要修改结构体定义,适合快速调试,能清晰看到对象间的引用关系。

方法2:自定义结构体的打印函数

通过给结构体添加:print-function选项,自定义打印逻辑,避免递归打印循环引用的槽位。比如只打印节点的数据和唯一标识(如内存地址),不展开prev和next的完整内容。

示例代码:

(defstruct (node (:print-function print-node))
  data
  next
  prev)

(defun print-node (node stream depth)
  (declare (ignore depth))
  (format stream "#<NODE data: ~a, addr: ~x>"
          (node-data node)
          (sb-kernel:get-lisp-obj-address node)))

此时打印节点会输出类似#<NODE data: "world", addr: 12345678>的内容,既不会触发循环,又能区分不同节点。如果需要查看引用关系,可以单独打印prev或next的标识。

内容的提问来源于stack exchange,提问作者Connor Krenzer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:46:04