Clojure:能否使用swap!返回原子值及自定义任意值?
解决Clojure swap!同时返回新值和自定义结果的问题
嘿,这个需求我之前也碰到过!不用额外创建一个原子来存结果,我们可以利用Clojure原子的CAS(比较并交换)特性,自己封装一个类似swap!但能同时返回自定义值的工具函数,既保证原子性又简洁。
核心思路
原生的swap!只能返回原子的新状态,但我们可以让更新函数同时计算出新状态和想要的自定义值,然后通过loop+compare-and-set!模拟swap!的原子性逻辑,最后把两者一起返回。
实现方案
首先写一个通用的工具函数:
(defn swap-with-result! [atom update-fn & args] (loop [] (let [old-state @atom ; 要求update-fn返回[新状态 自定义结果]的向量 [new-state custom-result] (apply update-fn old-state args)] (if (compare-and-set! atom old-state new-state) ; CAS成功,返回新状态和自定义结果 [new-state custom-result] ; 失败则重试,和原生swap!逻辑一致 (recur)))))
然后修改你的更新逻辑,让它返回包含新map和新增键的向量:
(swap-with-result! (atom {1 1 2 2 3 3 4 4 5 5}) (fn [m] (loop [] (let [i (rand-int 10)] (if (contains? m i) (recur) ; 返回[新map 新增的键i] [(assoc m i "ok") i])))))
调用这个函数后,你会得到类似[{1 1, 2 2, 3 3, 4 4, 5 5, 7 "ok"} 7]的结果——第一个元素是原子的新值,第二个就是你想要的新增键,同时原子已经被成功更新。
为什么这个方案更好
- 原子性:完全继承了原生
swap!的CAS重试逻辑,不会出现竞态条件 - 简洁:不需要维护额外的原子状态,所有逻辑在一次原子操作内完成
- 灵活:自定义结果可以是任何类型,不仅限于新增的键,适配各种场景
内容的提问来源于stack exchange,提问作者nha
相关产品推荐
相关产品推荐

