为什么 Clojure 1.3 说当我将变量声明为动态时变量未声明为动态?

发布于 2024-12-17 06:04:52 字数 1358 浏览 4 评论 0原文

我正在将工作 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 的结果;其次,在使用 Cc Cw 编译我的 core.clj 文件后,从 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"})

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

I'm porting working Clojure code (in a Leiningen project) from 1.2 to 1.3 and having problems. In addition to the code itself no longer working, I'm getting dozens of warning messages like this one:

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.

This is happening even though I have already made what look like the correct modifications to vars that I'm using to maintain state. For the error above, for example, the code already includes this:

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

I get these errors in two places: first, from the command line, as a result of executing lein swank; and second, from the Emacs REPL, after compiling my core.clj file using C-c C-w.

To be absolutely complete, here is my project.clj file:

(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"})

In addition to getting my code working, I'd like to understand why I'm getting these errors and why I'm getting them in both places. Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

紫﹏色ふ单纯 2024-12-24 06:04:52

这是一个简单的错字。

(def ^:dyanamic ...

应该是:

(def ^:dynamic ...

发生在我们所有人身上!

It's a simple typo.

(def ^:dyanamic ...

should be:

(def ^:dynamic ...

Happens to us all!

羅雙樹 2024-12-24 06:04:52

您可能需要考虑使用引用或原子而不是变量来维护状态。

引用 Clojure 文档

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

(强调我的。)

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

给出旨在作为反弹名称的 var 是一个常见的约定(但仅此而已)这个:*foobar*。由于这种约定,当编译器看到这样命名但未声明为动态的 var 时,它会向您发出警告。

总结一下:

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

You might want to consider using refs or atoms instead of vars to maintain state.

To quote the Clojure documentation:

Vars provide a mechanism to refer to a mutable storage location that can be dynamically rebound (to a new storage location) on a per-thread basis.

(Emphasis mine.)

Vars can be set to a new value (for the current thread) with the binding macro. Up to Clojure 1.2 any var could be rebound like this, but since Clojure 1.3 vars need to be explicitly declared as ^:dynamic to allow this. (As far as I know, the reason is a drastic speed-up of var look-ups for the common case of no rebinding.)

It is a common convention (but nothing more) to give vars that are intended to be rebound names like this: *foobar*. Because of this convention, the compiler gives you a warning when it sees a var named like this that is not declared dynamic.

To sum up:

  • If you just want to declare a value that does not change during runtime, use a var and drop the *'s around the name.
  • If you want to change the value on a per-thread basis, declare the var dynamic.
  • If you want to maintain global state (not per-thread), use one of the other referential types: atom, ref (if you need transactions) or agent (for asynchronous change).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文