如何在Leiningen用户repl中创建一个var set -able?

时间:2016-06-14 21:33:55

标签: clojure leiningen read-eval-print-loop thread-local

我在源文件中定义的命名空间中有动态var,如下所示:

(ns mystuff.log ...)

(def ^:dynamic *logging* #{})

我希望能够从REPL中set!这个var,以便同一源文件中的代码可以查看它。在此示例中,mystuff.log/log宏查看*logging*以决定是否打印给定表达式。在REPL中,(set! *logging* #{:whatever})会很方便,在会话期间多次更改其值。

如何让Leiningen的REPL允许这样做?默认情况下,set!这样的var会产生IllegalStateException,因为set!无法更改var的根绑定。 var必须是线程局部的,可由set!更改。

有没有办法告诉Leiningen将REPL包装成这样的东西,为var创建一个线程局部绑定?

(binding [mystuff.log/*logging* mystuff.log/*logging*]
  (the-leiningen-repl ...))

:init的{​​{1}}选项,简要解释here,似乎提供了接近的内容。但显然,REPL会调用:repl-options,这会为在REPL中输入的表达式建立线程局部绑定而为时已晚。

1 个答案:

答案 0 :(得分:2)

您可能需要alter-var-root,而不是set!。由于没有对REPL进行特殊设置或修改,您可以执行以下操作:

user> (def logging #{})
#'user/logging

user> (alter-var-root #'logging conj :my-new-logger)
#{:my-new-logger}

user> (alter-var-root #'logging conj :another-new-logger)
#{:my-new-logger :another-new-logger}

user> logging
#{:my-new-logger :another-new-logger}


#{:my-new-logger :another-new-logger}

set!仅修改var的当前线程绑定。 alter-var-root修改var的根绑定:在所有线程中共享的值,它不被每个线程绑定覆盖。*

*顺便说一下,这就是alter-var-root没有感叹号的原因。它遵循与修改根绑定的其他形式相同的约定,如def