我正在学习 Clojure,并且正在玩动态范围。我发现了一些事情:
- 将
{:dynamic true}
元数据添加到现有 Var 实际上并不会使 Var 动态化。我可以理解您为什么希望这样,但这可能会产生误导。 - 您可以查看 Var 是否实际上是动态的
(.isDynamic #'whatever)
- 您可以(但可能不应该?)更改 Var 是否是动态的
(.setDynamic #'whatever)
简而言之,看起来 Var 的动态特性存储在 clojure.lang.Var 类本身的内部,并且在 def 时间^:dynamic
设置元数据只会影响该内部状态。之后更改元数据似乎不会影响它。好的。
我在查看命名空间 clojure.core 中的动态变量时发现了这一点。我检查了该命名空间中的哪些 Vars:dynamic
设置了元数据:
user=> (def metadyn (map key (filter #(-> % key resolve meta :dynamic) (ns-publics 'clojure.core))))
#'user/metadyn
user=> metadyn
(*3 *2 *print-level* *data-readers* *e *print-length* *1 *verbose-defrecords*
*clojure-version* *default-data-reader-fn* pr)
比我预期的要少,缺少诸如*out*
and之类的东西*in*
。
我检查了哪些 Vars 实际上是动态的:
user=> (def realdyn (map key (filter #(-> % key resolve .isDynamic) (ns-publics 'clojure.core))))
#'user/realdyn
user=> realdyn
(*compile-path* *3 *2 *ns* *print-level* *allow-unresolved-vars* *data-readers*
*unchecked-math* *math-context* *read-eval* *compile-files* *command-line-args*
*warn-on-reflection* *e *flush-on-newline* *out* *print-length* *1 *file* *verbose-defrecords*
*clojure-version* *use-context-classloader* *err* *default-data-reader-fn* *agent* pr
*print-dup* *print-readably* *fn-loader* *print-meta* *in* *source-path* *compiler-options* *assert*)
还有很多。
因此,以下 Var 是动态的,但并未声称在其元数据中:
user=> (clojure.set/difference (set realdyn) (set metadyn))
#{*compile-path* *ns* *allow-unresolved-vars* *unchecked-math* *math-context* *read-eval*
*compile-files* *command-line-args* *warn-on-reflection* *flush-on-newline* *out* *file*
*use-context-classloader* *err* *agent* *print-dup* *print-readably* *fn-loader* *print-meta*
*in* *source-path* *compiler-options* *assert*}
我的问题很简单:这有什么意义吗,我错过了什么?或者,这只是 Clojure 实现中草率记账的一个例子吗?
没有实际用途;只是试图理解。