延长交换! Clojure中nil类型的行为

时间:2019-01-23 15:58:06

标签: clojure

让我们假设我有var atom-var

(def atom-val (atom []))

还假设原子的标准行为:

(swap! atom-val conj {:b "2"})
=> #object[clojure.lang.Atom 0x6500d3fd {:status :ready, :val [{:a "2"}]
(@atom-val)
=> #object[clojure.lang.Atom 0x6500d3fd {:status :ready, :val [{:a "2"}]

我想创建与使用nil对象相同的行为,但不执行任何操作:

(def atom-val nil)
(swap! atom-val conj "New val")

当然,我会得到一个NullPointerException。但是,我希望什么都没有发生,抑制它。我不需要每次都写try,只需要描述的行为即可。

我看到 swap!是一个函数, atom 是一个函数,atom返回 clojure.lang.IAtom ,clojure.lang。 IAtom是一个接口。我无法扩展接口。 如何获得描述的行为?

嗯,我有一个等于nil的全局动态变量

(def ^:dynamic  atom-val nil). 

无论何时创建线程(它是带有compojure的环形处理程序),我都会将atom-val绑定到

(defn func [handler] 
   (fn [request]
     (binding [atom-val (atom [])]
        (handler request)
    )
 )

所以,我有这样一种形式的不同功能:

(swap! atom-val conj "New val"). 

我可以在很多地方(不同功能的内部/外部)运行它。每次检查 atom-val 是否为null真的很糟糕。函数必须进行 swap!,但是有时 atom-val 无法正确初始化(当函数在绑定之前在环处理程序之外进行swap!)。 )。

所以我决定这样做:我想为Atom和nil(当atom-val nil 时)扩展 swap!协议。通过时,不得抛出NullPointerException。

3 个答案:

答案 0 :(得分:3)

您需要使用fnil。参见https://clojuredocs.org/clojure.core/fnil

示例:

(def atom-val nil)
(def nil-swap! (fnil swap! (atom [])))

(nil-swap! atom-val conj "New val") => ["New val"]

也不要忘记始终向The Clojure CheatSheet打开浏览器标签!

答案 1 :(得分:3)

如果您想要一个无所事事的原子,则可以编写:

(def noop-atom
  (reify clojure.lang.IAtom
    (reset [_ _])
    (swap [_ _])
    (swap [_ _ _])
    (swap [_ _ _ _])
    (swap [_ _ _ _ _])
    (compareAndSet [_ _ _])))

然后您可以将该原子用作动态变量的根值。

如果您的目标是在Ring请求/响应的生命周期内管理状态,则可以编写自定义middleware

答案 2 :(得分:1)

因此,您想swap!零吗?我不确定您采取任何行动的意思。

swap!的nil值绝对(至少对我而言)毫无意义;如果对您有用,则应检查原子真正是什么。也许您的意思是,当给定nil而不是原子引用时,swap!不会做任何事情。

如果是这样,那么您只需执行自己的功能即可为您做检查:

(defn nilable-swap!
  [a f]
  (when a (swap! a f)))

但是我真的不建议您这样做,如果这是您要执行的操作,则表明设计和控制流程不正确。当然,如果不确定,检查您的原子引用是否为nil确实有意义,但是您真的需要定期检查吗?真的没有什么意义可以让您知道获得原子参考的吗?

认为我可能已经回答了您的问题,但是如果我误解了,请随时进行澄清,我将更新/删除答案。