Clojure使用map值替换atom

3

我想把一个映射的值关联到一个原子中,可以这样做:

(def a (atom {}))
(swap! a assoc :key1 "value1" :key2 "value2")
  (defonce config (atom {}))
  (swap! config assoc :a "Aaa")
  (swap! config assoc :b "Bbb")

但这种方法很重复,并且会多次调用swap!函数。 我想实现的是这样的:

(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

我该怎么做?
How do I do that ?
1个回答

9
请参阅关于assoc的文档:
=> (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函数不能直接传入一个映射(map),而是需要传入键值对:

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! 可以使所有内容都成为原子级。
注意:merge 的行为与你想象的相同。
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}}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接