1

我正在学习 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 实现中草率记账的一个例子吗?

没有实际用途;只是试图理解。

4

1 回答 1

1

您在没有元数据的情况下标识的动态变量是在 Java 运行时中创建的(请参阅RT.java从第 180 行开始)。其他的在引导程序可用后在 Clojure 中创建def(即在 core.clj 和 core_print.clj 中)。

元数据可以稍后添加,在某些情况下是(例如*agent*有一个文档字符串),所以这不是一个完整的答案。正如您所指出的,我可以推测缺乏实际重要性使得调整引导中使用的变量的元数据成为低优先级。

于 2013-08-12T17:11:25.687 回答