如何在 Clojure 中拆分原子?

Dev*_*las 3 clojure

我有一个存储在原子中的集合,就像这样

(def numbers (atom #{1 2 3 4 5}))
Run Code Online (Sandbox Code Playgroud)

使用swap!. 在一个单独的线程中,我想要一个函数,从集合中提取和删除偶数并返回它们。

我可以这样做的一种方法是:

(let [{even true odd false} (group-by even? @numbers)]
  (reset! numbers odd)
  even)
Run Code Online (Sandbox Code Playgroud)

但是,这不是原子操作。numbers可以在group-by和之间变化reset!。有没有办法以原子方式执行此操作?

Dao*_*Wen 6

应用的函数swap!不需要是原子的。您应该可以使用swap!.

如果您只想留下奇数并取回偶数,您可以通过swap!仅返回赔率来应用该函数,然后这就是原子的值将被更新为的值。

剩下的问题是如何取回偶数。有很多方法可以做到这一点——我不确定什么是最好的。也许您可以在您的收藏中使用元数据?像这样的东西:

(def numbers (atom #{1 2 3 4 5}))

(defn atom-splitter [xs]
  (let [{even true odd false} (group-by even? xs)]
    (with-meta (set odd) {:evens (set even)})))

(swap! numbers atom-splitter)
Run Code Online (Sandbox Code Playgroud)

的价值@numbers是那么#{1 3 5}

(meta @numbers)IS {:evens #{2 4}}

由于swap!返回的是换入值,因此您可以确定返回值的元数据包含拆分集合的另一半。例如,以下是安全的:

(defn split-off-evens [a]
  (-> (swap! numbers atom-splitter) meta :evens))
Run Code Online (Sandbox Code Playgroud)

如果具有其原始值,则调用(split-off-evens numbers)返回。由于这仍然是 的正确用法,您可以假设 Clojure 处理所有线程安全问题。#{2 4}numbersatom