原子和条件映射更新

Mic*_*hal 2 clojure

我想更新一个简单的原子,比如:{:a 1}并且只返回新值swap!,只有当给定键已经存在时(否则返回nil).

这是我想出的最简单的解决方案:

(defn cond-assoc [store k v]
  (when (get @store k)
    (swap! store assoc k v)))
Run Code Online (Sandbox Code Playgroud)

但我觉得这不是真正的原子.在野外很多事情可能发生在(get @store k)swap!操作之间.还有比这更好的解决方案吗?

Shl*_*omi 5

你是对的,你的解决方案不是很原子的.要进行原子交换,请创建一个仅在需要时转换地图的简单函数:

(defn assoc-if-exists [m k v]
  (if (m k) (assoc m k v) m))
Run Code Online (Sandbox Code Playgroud)

请注意,这与原子或原子无关.要与原子一起使用,只需这样做

(def store (atom {:a 1}))
(swap! store assoc-if-exists :a 4) ;; {:a 4}, value changed
(swap! store assoc-if-exists :b 4) ;; {:a 4}, nothing added
Run Code Online (Sandbox Code Playgroud)

请注意,当密钥不存在时,这不会返回nil.如果您想要这种行为,可以检查返回的值是否包含密钥:

(defn atomic-assoc-or-nil [a k v]
  (let [r (swap! a assoc-if-exists k v)]
    (when (get r k) r)))
Run Code Online (Sandbox Code Playgroud)