我想更新一个简单的原子,比如:{: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!操作之间.还有比这更好的解决方案吗?
你是对的,你的解决方案不是很原子的.要进行原子交换,请创建一个仅在需要时转换地图的简单函数:
(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)