重新定义变量有哪些危险或缺点?

时间:2014-12-22 07:03:11

标签: binding clojure

我总是加载一个名称空间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/barbar然后使用新值foo,0.025,而不是原来的0.05。

我不确定是否对这种行为感到惊讶。我想重新定义使用def作为repl中的便利方便,但是作为普通代码中不应该做的事情。但是,我不确定为什么。以这种方式重新定义foo似乎可以毫无困难地使用lein run从命令行运行所有内容,通过require加载文件。

所以,我的问题是:这种做法的危险或其他缺点是什么 - 即。使用def重新定义变量?

(顺便说一句,我不会将^:dynamic添加到foo的定义中,因为我不需要线程本地绑定; foo的新值应该是如果我将^:const添加到foo的定义中,bar使用原始的0.05值,尽管我重新定义了foo,因为bar应该{{1}}在那种情况下。)

2 个答案:

答案 0 :(得分:3)

重新定义var不是线程安全的,不应在生产环境中完成。 similar question有一个很好的响应,可以深入了解潜在的原因。

答案 1 :(得分:1)

在Clojure中重新定义变量的主要缺点与线程安全性没有多大关系,更多的是与可变状态的固有危险有关。惯用语Clojure力求纯粹功能性,没有副作用。这使得更容易推理程序的逻辑 - 给定相同的输入,函数将始终产生相同的输出。

当您重新定义var时,您基本上将其视为可变全局变量。现在,使用该变量的代码的行为不仅取决于其输入,还取决于它相对于可能已更改该变量的其他代码的执行顺序。这个额外的时间维度使得你的程序更难以推理。

我将var重新定义为代码气味:在这种特殊情况下可能没问题,但应该表明你应该重新评估你的方法,看看是否有更好的方法。