为什么Clojure 1.3说变量在我声明它们是动态的时候没有被声明为动态的?

时间:2011-11-21 23:30:11

标签: dynamic clojure version compatibility leiningen

我正在将工作Clojure代码(在Leiningen项目中)从1.2移植到1.3并且遇到问题。除了代码本身不再有效之外,我还收到了许多类似这样的警告消息:

Warning: *tooltip-width* not declared dynamic and thus is not dynamically rebindable, 
but its name suggests otherwise. Please either indicate ^:dynamic *tooltip-width* 
or change the name.

这种情况正在发生,即使我已经对我正在用于维护状态的变量进行了正确的修改。例如,对于上面的错误,代码已包含以下内容:

(def ^:dyanamic *tooltip-width*   (* 1.8 *slip-width*))

我在两个地方遇到这些错误:首先,从命令行执行lein swank;第二,在使用core.clj编译C-c C-w文件后,从Emacs REPL开始。

绝对完整,这是我的project.clj文件:

(defproject infwb "1.0.0-SNAPSHOT"
  :description "an evolving, experimental workspace for manipulating infocards"
  :main infwb.core

  :dependencies [[org.clojure/clojure "1.3"]
             [seesaw "1.2.1"]
         [org.clojars.gw666/sxqj "beta2"]
         [org.clojars.gw666/piccolo2dcore "1.3"]
         [org.clojars.gw666/piccolo2dextras "1.3"]
         [com.miglayout/miglayout "3.7.4"]
         ]
  :dev-dependencies [[swank-clojure "1.3.2"]
             [org.clojars.weavejester/autodoc "0.9.0"]]
  :autodoc {:name "Infocard Workbench (InfWb)",
        :web-src-dir "https://github.com/gw666/infwb/blob"})

除了让我的代码正常工作之外,我还想了解为什么我会收到这些错误为什么我会在两个地方收到它们。谢谢你的帮助。

2 个答案:

答案 0 :(得分:15)

这是一个简单的错字。

(def ^:dyanamic ...

应该是:

(def ^:dynamic ...

发生在我们所有人身上!

答案 1 :(得分:11)

您可能需要考虑使用refs或atoms而不是vars来维持状态。

引用Clojure documentation

  

Vars提供了一种机制来引用可变存储位置,该位置可以在每线程的基础上动态反弹(到新的存储位置)。

(强调我的。)

可以使用binding宏将Vars设置为新值(对于当前线程)。直到Clojure 1.2,任何var都可以像这样反弹,但是因为Clojure 1.3 vars需要明确声明为^:dynamic才允许这样做。 (据我所知,原因是对于没有重新绑定的常见情况,会大幅加快var查找。)

这是一个常见的约定(但仅此而已),以提供像这样的反弹名称的变量:*foobar*。由于这种约定,编译器在看到名为这样的未声明为动态的var时会给出警告。

总结一下:

  • 如果您只想声明一个在运行时不会改变的值,请使用var并删除名称周围的*。
  • 如果要基于每个线程更改值,请声明var dynamic。
  • 如果要维护全局状态(不是每个线程),请使用其他参考类型之一:atomref(如果需要事务处理)或agent(用于异步更改)。