让我们假设我有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。
答案 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确实有意义,但是您真的需要定期检查吗?真的没有什么意义可以让您知道获得原子参考的吗?
我认为我可能已经回答了您的问题,但是如果我误解了,请随时进行澄清,我将更新/删除答案。