在单个交换语句中更新Clojure原子的多个元素?

时间:2014-03-10 23:47:08

标签: clojure

我有一个原子,它有两个部分。

(def thing (atom {:queue '() :map {}}))

我想更新:queue和:map in one atomic,以防止它们脱离同步。

单独排队:

(swap! thing update-in [:queue] (list 1))

(来自这个问题:How to append to a nested list in a Clojure atom?

单独地图:

(swap! thing assoc-in [:map 1] (:key :value))

(来自这个问题:Using swap to MERGE (append to) a nested map in a Clojure atom?

如何在单个交换语句中执行这些操作? (假设这会阻止他们脱离同步?)

2 个答案:

答案 0 :(得分:10)

你想做一个改变,对吗?你可以把这个改变写成纯粹的功能吗?您需要做的就是编写该函数,并将其作为参数传递给swap!

(defn take-from-queue [{q :queue, m :map}]
  {:queue (rest q), :map m (assoc m :new-task (first q))})

(swap! thing take-from-queue)

我当然不知道你真正希望你的函数体是做什么的,所以我已经编造了一些不会抛出异常的东西。

答案 1 :(得分:1)

假设你有一个哈希映射原子:

(def m1 (atom {:a "A" :b "B"})) 

要同时更改:a:b,将其值更改为不同的值(例如数字1和2),请使用此函数:

(defn my-swap! [params]
  (swap! m1 (fn [old new] new) params))

,像这样:

(my-swap! {:a 1 :b 2}) ;=> {:a 1, :b 2}

使用以下功能和执行可以实现相同的效果:

(defn my-multi-swap! [params1 params2]
  (swap! m1 (fn [old new1 new2] new2) params1 params2))

(my-multi-swap! {} {:a 1 :b 2}) ;=> {:a 1, :b 2}

如果要忽略旧值,通常会使用reset!。我们在这里使用它:

(defn my-merge-swap! [params]
  (swap! m1 (fn [old new] (merge old new)) params))

(my-merge-swap! {:b 3}) ;=> {:a "A", :b 3}

交换的第一个参数! function 是atom的现有值,您必须传入一个或多个额外参数,您可以使用这些参数为atom赋予其新值。