8

如果我尝试在我的 emacs cider-repl 中评估以下代码,则会按预期返回 nil,但不会在 repl 缓冲区或控制台中进行任何打印。我怎样才能按预期打印出来?

(dotimes [i 5]                                                                                                                                        
  (.start                                                                                                                                             
   (Thread.                                                                                                                                           
    (fn []                                                                                                                                             
      (Thread/sleep (rand 500))                                                                                                                       
      (println (format "Finished %d on %s" i (Thread/currentThread)))))))
;=> nil

但是,这很好用:

(println (format "Finished 1 on %s" (Thread/currentThread)))
;=> Finished 1 on Thread[nREPL-worker-18,5,main]
----------- mini-buffer -----------------
nil
4

4 回答 4

11

的行为println是使用动态绑定的 var*out*作为其输出流。emacs 动态绑定*out*到 repl 缓冲区以获取在 repl 缓冲区中评估的代码,但是如果您创建一个线程,该线程将*out*获得 的根绑定*out*,在 cider 的情况下,它将不是 repl 缓冲区。

如果您使用 启动 repl cider-jack-in,当您查看缓冲区列表时,应该有一个名称类似于*nrepl-server*包含根*out*绑定输出的缓冲区。这是我运行代码后的内容:

nREPL server started on port 52034 on host 127.0.0.1 - nrepl://127.0.0.1:52034
Finished 1 on Thread[Thread-9,5,main]
Finished 0 on Thread[Thread-8,5,main]
Finished 2 on Thread[Thread-10,5,main]
Finished 3 on Thread[Thread-11,5,main]
Finished 4 on Thread[Thread-12,5,main]

如果您没有使用cider-jack-in,输出将打印到您启动 nrepl 进程的终端。

于 2014-11-04T20:10:36.683 回答
10

*out*是决定输出println和类似函数去向的动态变量。它是线程绑定到某个地方,导致东西被发送回 emacs 以供 cider 显示;如果您启动一个新线程,则该绑定不存在,并且输出到其他地方(可能到在后台启动的 nrepl 服务器 emacs/leiningen 的标准输出)。

您可以通过几种方式解决这个问题。您可以从父线程捕获 的值*out*,然后将其传递给闭包中的子线程,然后重新绑定*out*到它:

(let [out *out*] 
  (.start (Thread. (fn [] 
                     (binding [*out* out]
                        (println "test"))))))

或者您可以使用 afuture而不是自己启动线程:Clojure 自动将相关的线程本地绑定传递给为将来启动的新线程。

于 2014-11-04T20:11:10.400 回答
8

在 repl 中执行下面的表达式,那么所有的输出都会在 repl 中结束:

(alter-var-root #'*out* (constantly *out*))

原答案:

https://groups.google.com/d/msg/cider-emacs/bIVBvRnGO-U/nDszDbGoVzgJ

于 2014-11-21T07:26:20.453 回答
0

如果您使用的是 Figwheel,那么在 ring 处理程序(实际上类似于上面显示的 Threads 示例)中执行 prn/println 也可以被 Fighweel 本身吞下。检查您的项目的 project.clj(在 :figwheel 映射中查找键 :server-logfile ),您可以在其中控制是否应该转到 repl 或日志文件。请注意,这仅适用于您使用无花果的情况,否则打印到 REPL 当然可以正常工作。

有关更多详细信息,请参阅我对这个问题的回答:Output compojure server print statements into figwheel terminal?

于 2017-06-27T15:57:55.640 回答