我总是加载一个名称空间not-really-constants
。除其他定义外,它还包含:
(def foo 0.05)
另一个名称空间包含
(ns other-ns
(require [not-really-constants :as cn]))
(defn bar [x] (* x cn/foo))
但是,有时我希望foo
具有不同的值。所以我加载一个包含
(in-ns 'not-really-constants)
(def foo 0.025)
然后我在通常被调用的地方调用other-ns/bar
。 bar
然后使用新值foo
,0.025,而不是原来的0.05。
我不确定是否对这种行为感到惊讶。我想重新定义使用def
作为repl中的便利方便,但是作为普通代码中不应该做的事情。但是,我不确定为什么。以这种方式重新定义foo
似乎可以毫无困难地使用lein run
从命令行运行所有内容,通过require
加载文件。
所以,我的问题是:这种做法的危险或其他缺点是什么 - 即。使用def
重新定义变量?
(顺便说一句,我不会将^:dynamic
添加到foo
的定义中,因为我不需要线程本地绑定; foo
的新值应该是如果我将^:const
添加到foo
的定义中,bar
使用原始的0.05值,尽管我重新定义了foo
,因为bar
应该{{1}}在那种情况下。)
答案 0 :(得分:3)
重新定义var不是线程安全的,不应在生产环境中完成。 similar question有一个很好的响应,可以深入了解潜在的原因。
答案 1 :(得分:1)
在Clojure中重新定义变量的主要缺点与线程安全性没有多大关系,更多的是与可变状态的固有危险有关。惯用语Clojure力求纯粹功能性,没有副作用。这使得更容易推理程序的逻辑 - 给定相同的输入,函数将始终产生相同的输出。
当您重新定义var时,您基本上将其视为可变全局变量。现在,使用该变量的代码的行为不仅取决于其输入,还取决于它相对于可能已更改该变量的其他代码的执行顺序。这个额外的时间维度使得你的程序更难以推理。
我将var重新定义为代码气味:在这种特殊情况下可能没问题,但应该表明你应该重新评估你的方法,看看是否有更好的方法。