-->

如何覆盖引用类型的println行为(How to override println behavio

2019-09-16 07:55发布

我有我使用创造了一个循环图dosyncref-set 。 当我通过这个来println我得到一个java.lang.StackOverflowError ,因为我所期望的,因为它有效地试图打印无限嵌套结构。

我发现,如果我这样做(str my-ref)它创造的东西,看起来像vertex@23f7d873而实际上并没有试图穿越结构和打印出来的一切,所以这解决了眼前的意义上的问题,但只有当帮助我很小心,我打印的内容到屏幕上。 我希望能够调用(println my-graph)它打印的ref为某些类型的自定义文本(可能涉及的str ),以及其他非参考的东西一般。

目前,我有一个打印自身的结构中的每个元素和完全跳过打印自定义打印功能ref 。 (事实证明,在寻找vertex@23f7d873实际上不是非常有用)。 这是难以使用并阻碍大大做的东西随便检查在REPL,还可以防止的Emacs督察从看的东西,而我在我swank.core/break调试啄。

一个细节是ref居然是在一个价值defstruct也包含我想正常打印一些其他的东西。

所以我想我应该去什么路了。 我看到这些选项:

  1. 弄清楚extend-type和应用CharSequence协议来我defstruct编结构,这样,当它遇到一个ref它工作正常。 这仍然需要结构,当它涉及到一个特殊情况的场逐场检查ref ,但它至少本地化问题的结构,而不是任何包含的结构。
  2. 弄清楚如何重写CharSequence协议时遇到一个ref 。 这使得更加本地化的行为,并允许我在REPL查看循环裁判,即使它不是一个结构里面。 这是我的首选方案。
  3. 弄清楚如何做的东西toString我相信这是所谓的在一定程度上,当我做println 。 我最无知的这个选项。 漂亮的无知其他的人太多,但我一直在读Joy of Clojure ,我现在都启发。

同样这个解决方案应该适用于printpprint和其他任何通常BARF试图打印循环REF时。 我应该采用什么样的策略?

非常感谢任何输入。

Answer 1:

你要做的是创建一个新的命名空间,并定义模型的方式Clojure的打印对象自己的打印功能,并且默认为Clojure的方法。

详细:

    创建不包括PR-STR和印刷方法的纳秒。 创建一个多方法的打印方法(副本到底是什么在clojure.core)创建一个默认的方法,仅仅委托给clojure.core /打印方法创建clojure.lang.Ref的方法不递归打印一切

作为奖励,如果您使用的Clojure 1.4.0,您可以使用标记文本,使阅读在输出也是可能的。 您将需要重写*data-readers*地图自定义标签,并返回一个Ref对象的功能。 你想也需要重写读串的行为,以确保绑定被调用*data-readers*

我已经提供了java.io.File的一个例子

 (ns my.print
   (:refer-clojure :exclude [pr-str read-string print-method]))

 (defmulti print-method (fn [x writer]
         (class x)))

 (defmethod print-method :default [o ^java.io.Writer w]
       (clojure.core/print-method o w))

 (defmethod print-method java.io.File [o ^java.io.Writer w]
       (.write w "#myprint/file \"")
       (.write w (str o))
       (.write w "\""))

 (defn pr-str [obj]
   (let [s (java.io.StringWriter.)]
     (print-method obj s)
     (str s)))

 (defonce reader-map
   (ref {'myprint/file (fn [arg]
               (java.io.File. arg))}))

 (defmacro defdata-reader [sym args & body]
   `(dosync
     (alter reader-map assoc '~sym (fn ~args ~@body))))

 (defn read-string [s]
   (binding [*data-readers* @reader-map]
     (clojure.core/read-string s)))

现在,可以调用像这样(println (my.print/pr-str circular-data-structure))



Answer 2:

我发现我的解决方案-只要创建一个重载一个多方法clojure.core/print-method为每个特定的类型,并从多方法中调用通用函数。 在这种情况下,每个多重方法调用通用print-graph-element它知道如何处理引用做(这只是打印出来的引用对象的哈希值,而不是试图打印出来的引用对象的值)。 在这种情况下,我假设印刷方法的调度功能只(type <thing>)所以它会调度类型,这就是我如何写多重方法。 其实,我找不到任何文档即是这样的印刷方法调度是如何工作的,但可以肯定的行为似乎与这样的。

该解决方案允许我只需键入对象,如名称v0 (这是由在REPL和印刷法(使顶点)涂蜡得到由REPL调用,从而防止我的StackOverflow的错误。

(defmethod clojure.core/print-method vertex [v writer]
  (print-graph-element v))
(defmethod clojure.core/print-method edge [e writer]
  (print-graph-element e))


Answer 3:

如果你只是想能够打印数据结构与循环,尝试设置*print-level*限制打印机将有多深下降。

user=> (def a (atom nil))
#'user/a
user=> (set! *print-level* 3)
3
user=> (reset! a a)
#<Atom@f9104a: #<Atom@f9104a: #<Atom@f9104a: #>>>

还有一个*print-length*当你在处理与无限长度的数据,可能是有用的变种。



文章来源: How to override println behavior for reference types