Clojure 模仿中的狡猾行为*

Clojure 模仿中的狡猾行为*,clojure,mocking,Clojure,Mocking,我有以下代码: (def x 10) (def io (java.io.StringWriter.)) (with-redefs [x 11] (with-redefs [io (java.io.StringWriter.)] (.write io "one")) (with-redefs [io (java.io.StringWriter.)] (.write io "two") (.toString io))) (with-redefs [x 11]

我有以下代码:

(def x 10)

(def io (java.io.StringWriter.))

(with-redefs [x 11]
  (with-redefs [io (java.io.StringWriter.)]
    (.write io "one"))
  (with-redefs [io (java.io.StringWriter.)]
    (.write io "two")
    (.toString io)))

(with-redefs [x 11]
  (with-redefs [*out* (java.io.StringWriter.)]
    (print "one"))
  (with-redefs [*out* (java.io.StringWriter.)]
    (print "two")
    (.toString *out*)))

第一个redefs块按预期返回“2”。第二个返回“onetwo”。这就好像出于某种原因,它正在重新利用同样的被嘲笑的**out*。这是预期的行为吗?

问题是您关心的
*out*
是一个线程本地值,而不是根值。尝试:

(with-redefs [x 11]
  (binding [*out* (java.io.StringWriter.)]
    (print "one"))
  (binding [*out* (java.io.StringWriter.)]
    (print "two")
  (.toString *out*)))

带有redefs的
宏只改变根绑定;任何线程本地绑定都不受影响。当REPL服务器执行代码时,它是在将
*out*
重新绑定到特定于客户端的写入程序的上下文中执行的,这样就可以捕获输出并将其发送回客户端进行显示(否则它将转到服务器的stdout)。如果从命令行而不是REPL运行,原始代码可能会工作。

值得一提的是out str宏,其中out绑定到新的StringWriter。第二个块不返回“onetwo”-它打印“onetwo”,并将默认对象返回到PrintWriter对象的字符串表示形式。好的,它打印“onetwo”。但它也返回“onetwo”。请参阅:(=“onetwo”(带redefs[x11](带redefs[out(java.io.StringWriter.))(打印“one”)(带redefs[out(java.io.StringWriter.)](打印“two”)(.toString out)))返回true。那么,在我们的REPL版本中可能会有所不同。这在我的回复中不起作用。