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

如何在print-object方法中正确使用格式控制参数打印树状CLOS对象

解决方案:递归缩进打印Rope二叉树结构

要实现Rope节点的递归缩进打印,核心是通过动态变量跟踪缩进级别,在递归打印子节点时递增缩进量,同时调整print-object方法的格式输出逻辑。

修改后的完整代码

(defvar *rope-indent* 0
  "动态变量,跟踪当前打印的缩进级别,单位为空格数")

(defclass rope ()
  ((depth :type fixnum :initform 0 :initarg :depth :reader rope-depth)
   (weight :type fixnum :initform 0 :initarg :weight :reader rope-weight)))

(defclass rope-leaf (rope)
  ((string :type string :initarg :string :reader rope-string)))

(defclass rope-node (rope)
  ((left :type rope  :initarg :left :reader rope-left)
   (right :type rope :initarg :right :reader rope-right)))

(defmethod print-object ((object rope) stream)
  (print-unreadable-object (object stream :type t :identity nil)
    ; 输出当前缩进量对应的空格
    (format stream "~v@t" *rope-indent*)
    (with-slots (depth weight) object
      (format stream "depth: ~a weight: ~a" depth weight))))

(defmethod print-object ((object rope-node) stream)
  (call-next-method)
  (with-slots (left right) object
    ; 换行后打印左子节点,缩进+2
    (format stream "~%")
    (let ((*rope-indent* (+ *rope-indent* 2)))
      (format stream "left: ~a" left))
    ; 换行后打印右子节点,缩进+2
    (format stream "~%")
    (let ((*rope-indent* (+ *rope-indent* 2)))
      (format stream "right: ~a" right))))

(defmethod print-object ((object rope-leaf) stream)
  (print-unreadable-object (object stream :type t :identity nil)
    (format stream "~v@t" *rope-indent*)
    (with-slots (depth weight string) object
      (format stream "depth: ~a weight: ~a ~s" depth weight string))))

实现原理

  1. 动态变量传递缩进状态
    使用*rope-indent*动态变量记录当前需要缩进的空格数,每次递归打印子节点时,通过let绑定将缩进量增加2,递归结束后自动恢复原缩进值(利用动态变量的作用域特性)。

  2. 格式指令控制缩进输出
    使用format的~v@t指令:

    • ~v表示取后续参数的值作为格式参数
    • @t表示输出指定数量的空格实现对齐
      配合*rope-indent*的值,就能在每个节点前输出对应长度的缩进。
  3. 调整print-unreadable-object行为
    添加:identity nil参数,避免打印对象的内存地址,专注于展示结构信息;同时确保每个节点的输出在独立行,配合缩进形成清晰的树状层级。

测试示例

(let* ((leaf1 (make-instance 'rope-leaf :depth 1 :weight 5 :string "hello"))
       (leaf2 (make-instance 'rope-leaf :depth 1 :weight 5 :string "world"))
       (node (make-instance 'rope-node :depth 2 :weight 5 :left leaf1 :right leaf2)))
  (print node))

预期输出

#<ROPE-NODE depth: 2 weight: 5
  left: #<ROPE-LEAF depth: 1 weight: 5 "hello">
  right: #<ROPE-LEAF depth: 1 weight: 5 "world">>

原代码问题分析

  • 缺少缩进状态跟踪:递归打印子节点时没有传递缩进信息,导致所有节点在同一层级输出。
  • 格式指令使用错误:原代码中~<~%left: ~a ~%right: ~a~>需要接收一个列表参数(正确用法是(format stream "~<~%left: ~a ~%right: ~a~>" (list left right))),但即使修正也无法解决缩进问题,核心还是没有跟踪缩进级别。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:27:01