在Clojure中使用自定义方法打印记录

时间:2013-03-02 21:14:42

标签: clojure pretty-print multimethod pprint

在Clojure 1.5.0中,如何为我自己的记录类型提供自定义漂亮的打印机,用defrecord定义。

(defrecord MyRecord [a b])

(defmethod print-method MyRecord [x ^java.io.Writer writer]
  (print-method (:a x) writer))

(defmethod print-dup MyRecord [x ^java.io.Writer writer]
  (print-dup (:a x) writer))

(println (MyRecord. 'a 'b)) ;; a -- OK
(clojure.pprint/pprint (MyRecord. 'a 'b)) ;; {:a a, :b b} -- not OK, I want a

我希望clojure.pprint/pprint也可以使用我的cutom打印机(现在,它应该只是打印出记录字段a中的任何内容,以便进行说明)。

3 个答案:

答案 0 :(得分:9)

clojure.pprint命名空间使用不同的调度机制,然后使用clojure.core打印功能。您需要使用with-pprint-dispatch来自定义pprint。

(clojure.pprint/with-pprint-dispatch print  ;;Make the dispatch to your print function
  (clojure.pprint/pprint (MyRecord. 'a 'b)))

要自定义简单调度程序,请添加以下内容:

(. clojure.pprint/simple-dispatch addMethod MyRecord pprint-myrecord)

答案 1 :(得分:3)

这一直非常混乱,问题的不同部分的正确答案遍布各地,所以我把它们放在一起,希望有人可以节省一些时间。

我详细介绍了为defrecord定义多方法print-methodprint-dupsimple-dispatch以及设置动态变量*print-pprint-dispatch**print-dup*的所有排列方式。我在prpprint中放了一个示例defrecord,并提出了以下流程图。现在我可以立刻看到一切,这是有道理的。

enter image description here

排列代码是蛮力;我只是看了一下输出并直接创建了Visio图。没什么好看的。

(ns print-test
  (:require [clojure.pprint :as pp]))


(defrecord tr000 [val])
(defrecord tr001 [val])
(defrecord tr010 [val])
(defrecord tr011 [val])
(defrecord tr100 [val])
(defrecord tr101 [val])
(defrecord tr110 [val])
(defrecord tr111 [val])


;;(defmethod print-method       tr000 [obj writer]  (.write writer "tr000 print-method"))
;;(defmethod print-dup          tr000 [obj writer]  (.write writer "tr000 print-dup"))
;;(defmethod pp/simple-dispatch tr000 [obj]         (.write *out* "tr000 simple-dispatch"))

;;(defmethod print-method       tr001 [obj writer]  (.write writer "tr001 print-method"))
;;(defmethod print-dup          tr001 [obj writer]  (.write writer "tr001 print-dup"))
(defmethod pp/simple-dispatch tr001 [obj]         (.write *out* "tr001 simple-dispatch"))

;;(defmethod print-method       tr010 [obj writer]  (.write writer "tr010 print-method"))
(defmethod print-dup          tr010 [obj writer]  (.write writer "tr010 print-dup"))
;;(defmethod pp/simple-dispatch tr010 [obj]         (.write *out* "tr010 simple-dispatch"))

;;(defmethod print-method       tr011 [obj writer]  (.write writer "tr011 print-method"))
(defmethod print-dup          tr011 [obj writer]  (.write writer "tr011 print-dup"))
(defmethod pp/simple-dispatch tr011 [obj]         (.write *out* "tr011 simple-dispatch"))

(defmethod print-method       tr100 [obj writer]  (.write writer "tr100 print-method"))
;;(defmethod print-dup          tr100 [obj writer]  (.write writer "tr100 print-dup"))
;;(defmethod pp/simple-dispatch tr100 [obj]         (.write *out* "tr100 simple-dispatch"))

(defmethod print-method       tr101 [obj writer]  (.write writer "tr101 print-method"))
;;(defmethod print-dup          tr101 [obj writer]  (.write writer "tr101 print-dup"))
(defmethod pp/simple-dispatch tr101 [obj]         (.write *out* "tr101 simple-dispatch"))

(defmethod print-method       tr110 [obj writer]  (.write writer "tr110 print-method"))
(defmethod print-dup          tr110 [obj writer]  (.write writer "tr110 print-dup"))
;;(defmethod pp/simple-dispatch tr110 [obj]         (.write *out* "tr110 simple-dispatch"))

(defmethod print-method       tr111 [obj writer]  (.write writer "tr111 print-method"))
(defmethod print-dup          tr111 [obj writer]  (.write writer "tr111 print-dup"))
(defmethod pp/simple-dispatch tr111 [obj]         (.write *out* "tr111 simple-dispatch"))


(def t000 (->tr000 10))
(def t001 (->tr001 20))
(def t010 (->tr010 30))
(def t011 (->tr011 40))
(def t100 (->tr100 50))
(def t101 (->tr101 60))
(def t110 (->tr110 70))
(def t111 (->tr111 80))
(def recs [t000 t001 t010 t011 t100 t101 t110 t111])


(def dt (java.time.LocalTime/now))
(defmethod print-dup java.time.LocalTime [obj writer] (.write writer "datetime_dup"))

(println "(pr ...) outputs the following")
(doseq [rec recs]
  (doseq [prppd [nil #(.write *out* "pprint-dispatch with" %)]]
    (binding [pp/*print-pprint-dispatch*
              (if prppd #(.write *out* (str "pprint-dipatch-with" %))
                  pp/*print-pprint-dispatch*)]
      (doseq [pd [false true]]
        (binding [*print-dup* pd]
          (let [ppdstr (format "%6s" (boolean pp/*print-pprint-dispatch*))
                dupstr (format "%6s" *print-dup*)
                outstr (pr-str rec)]
            (binding [*print-dup* false]
              (println ppdstr dupstr ":" outstr))))))))

(println "\n(pprint ...) outputs the following")
(doseq [rec recs]
  (doseq [prppd [false true]]
    (binding [pp/*print-pprint-dispatch*
              (if prppd #(.write *out* (str "pprint-dipatch-with" %))
                  pp/*print-pprint-dispatch*)]
      (doseq [pd [false true]]
        (binding [*print-dup* pd]
          (let [outstr
                (with-out-str
                  (pp/pprint {:ppdstr prppd
                              :dupstr pd
                              :dt dt
                              :strobj rec}))]
            (binding [*print-dup* false]
              (println outstr "\n"))))))))

答案 2 :(得分:0)

可能不理想,但我找不到比prpr-str更好的内容。

示例REPL会话:

  (ns my-ns)

  (defprotocol Foo
    (bazfn [this]))

  (defrecord Bar [a]
    Foo
    (bazfn [this] 123))


  (pr-str (Bar. "ok")) ;;=> "#my_ns.Bar{:a \"ok\"}"
  (pr (Bar. "ok"))     ;; prints the same as above