正确的表达式定义

Correct def for expression

我有这个功能:

(defn get-validator []
  (UrlValidator. (into-array ["https"])))

我希望它只被计算一次,在第一次调用时,然后 return 结果。哪种写法更好:

(def get-validator (UrlValidator. (into-array ["https"])))

(def ^:const get-validator (UrlValidator. (into-array ["https"])))

(defonce get-validator (UrlValidator. (into-array ["https"])))

或者有其他更好的方法吗?文档表明 defonce 是正确的,但没有明确说明。

首先,def 设置一个具有给定名称和可选的变量 当命名空间为 loaded/compiled 时,在该 var 中给出“init”值 (注意loading基本没有太大区别 和编译,这就是为什么你不想拥有的原因 def).

中的副作用

三个版本大体相同,区别如下:

  • :^const 允许内联这个值;所以这会影响以下 形式,当它们被编译时,可能会提高性能 以下代码
  • defonce 防止一旦命名空间被再次重新定义 var 重新加载;如果你 def 可变状态,这是最有用的,你 想在重新加载代码后生存下来

无论如何,第一次需要ns,都会执行代码 初始化变量。然后它基本上就不管了(想象一个静态的 属性 在带有静态初始值设定项的 Java class 中)。

综上所述:如果 UrlValidator 有内部状态,你可能仍然是 最好在需要时使用函数创建一个新函数。

另一种方法,假设 UrlValidator. 是参照透明的,是使用 clojure.core/memoize.

所以

(defn get-validator []
  (UrlValidator. (into-array ["https"])))
(def uval (memoize get-validator))

然后在需要验证器时使用 (uval)。由于记忆,get-validator 只会被调用一次。

这种方法在第一次执行 (uval) 时只会调用一次 UrlValidator.。所有其他建议将在加载命名空间时调用一次 UrlValidator.