避免覆盖变量名称

时间:2011-09-16 22:28:05

标签: clojure

在我正在处理的特定命名空间上,我开始耗尽函数名称。如果我重用一个已绑定到同一命名空间中的函数的符号,是否有一种方法可以获得类似于我从另一个命名空间覆盖符号的警告?

3 个答案:

答案 0 :(得分:4)

如果这是一个问题,你愿意替换(一组)核心宏,你可以尝试这种方法:

(ns huge.core
  (:refer-clojure :exclude [defn]))

(defmacro defn [name & defn-tail]
  (assert (nil? (resolve name))
          (str "Attempting to redefine already defined Var "
               "#'" (.name *ns*) "/" name))
  `(clojure.core/defn ~name ~@defn-tail))

然后,任何使用defn重新定义现有Var的尝试都将失败:

user=> (defn foo [] :foo)
#'user/foo
user=> (defn foo [] :bar)
AssertionError Assert failed: Attempting to redefine already defined Var #'user/foo
(nil? (resolve name))  user/defn (NO_SOURCE_FILE:2)

您可以类似地替换defmacro;在这种情况下,您必须在定义自己的变体时调用clojure.core/defmacro

简单,朴素的def是一种特殊的形式,并从编译器中获得魔法处理,因此您仍然可以用它覆盖现有的Vars。如果您想防止该侧翼上的名称冲突,您可以使用类似的自定义断言切换到defvar(以前在clojure.contrib.def中可用)。

答案 1 :(得分:2)

这不是您的问题的答案,但可能有助于避免此问题,具体取决于您的命名空间中的函数的使用方式。您可以使用 letfn 将它们转换为本地函数,允许您为仅在另一个函数的上下文中使用的函数重用名称。

(defn main-fn [x]
  (letfn [(secondary-fn [x] (* x x))
          (another-fn [x] (secondary-fn (inc x)))]
    (/ (another-fn x) 4)))

答案 2 :(得分:1)

即使您将自己局限于单字符函数名称,也不会有用完的危险,因为(大约)有64,000个Unicode字符,其中任何一个都是有效的函数名称。

鉴于你实际上可以拥有一万个字符长的名字,你就更安全了。