关于atomic:带有映射值的Clojure交换atom

Clojure swap atom with map values

我想assoc将地图的值添加到atom中。
我可以这样做:

1
2
3
  (defonce config (atom {}))
  (swap! config assoc :a"Aaa")
  (swap! config assoc :b"Bbb")

但是它是重复的,并且多次调用swap!
我想做这样的事情:

1
2
3
4
(swap! config assoc  {:a"Aaa"
                      :b"Bbb"})
;; this doesn't work :
;; Exception in thread"main" clojure.lang.ArityException: Wrong number of args (2) passed to: core$assoc

我该怎么做?


请参阅assoc

的文档

1
2
3
4
5
6
7
8
9
=> (doc assoc)
-------------------------
clojure.core/assoc
([map key val] [map key val & kvs])
  assoc[iate]. When applied to a map, returns a new map of the
    same (hashed/sorted) type, that contains the mapping of key(s) to
    val(s). When applied to a vector, returns a new vector that
    contains val at index. Note - index must be <= (count vector).
nil

assoc不拍摄地图。它需要成对的键和值:

1
2
3
4
5
6
user=> (assoc {} :a 1 :b 2)
{:a 1, :b 2}
user=> (let [x (atom {})]
                    #_=> (swap! x assoc :a 1 :b 2)
                    #_=> x)
#object[clojure.lang.Atom 0x227513c5 {:status :ready, :val {:a 1, :b 2}}]

顺便说一句,您应该始终将对原子的更新隔离到单个swap!中。通过如上所述进行两次交换,您可以允许其他线程潜在地破坏所引用的数据。单个swap!使所有内容保持原子性。

N.B。 merge的行为与您想象的一样:

1
2
3
4
5
6
user=> (merge {} {:a 1 :b 1})
{:a 1, :b 1}
user=> (let [x (atom {})]
                    #_=> (swap! x merge {:a 1 :b 2})
                    #_=> x)
#object[clojure.lang.Atom 0x1be09e1b {:status :ready, :val {:a 1, :b 2}}]