7

我正在将工作 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.

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

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

我在两个地方得到这些错误:首先,从命令行,作为执行的结果lein swank;其次,来自 Emacs REPL,在core.clj使用C-c C-w.

为了绝对完整,这是我的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"})

除了让我的代码正常工作之外,我还想了解为什么会出现这些错误以及为什么会在这两个地方都出现这些错误。谢谢你的帮助。

4

2 回答 2

16

这是一个简单的错字。

(def ^:dyanamic ...

应该:

(def ^:dynamic ...

发生在我们所有人身上!

于 2011-11-21T23:34:08.080 回答
12

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

引用Clojure 文档

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

(强调我的。)

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

给 var 提供旨在作为反弹名称的常见约定(但仅此而已),如下所示:*foobar*. 由于这个约定,当编译器看到一个像这样命名但没有声明为动态的变量时,它会给你一个警告。

总结一下:

  • 如果您只想声明一个在运行时不会更改的值,请使用 var 并在名称周围删除 *。
  • 如果要基于每个线程更改值,请声明 var 动态。
  • 如果要维护全局状态(不是每个线程),请使用其他引用类型之一:atomref(如果需要事务)或agent(用于异步更改)。
于 2011-11-22T09:11:37.450 回答