假设我有以下一段(伪造的)Clojure代码:
(def c (clojure.lang.Atom. [nil nil]))
(swap! c
(fn [[x y]]
["done", (second (swap! c (fn [[x y]] [x y])))]))
我希望它可以按以下方式工作:
Clojure对c
进行拆箱以找到[nil nil]
,并将其传递到外部fn
。
外部fn
调用swap!
,将c
拆箱以找到[nil nil]
,并将此值传递给内部fn
。
内部fn
返回[nil nil]
。对swap!
的内部调用将其交换为c
的新值。
外部fn
返回值["done" nil]
。
外部swap!
尝试访问compare-and-set!
,发现c
的当前值[nil nil]
与旧值{{ 1}},那么它成功了,交换了[nil nil]
。
但是实际上,这段代码会永远循环:外循环不断重试。
这是为什么?我的心理模型缺少什么?
答案 0 :(得分:3)
Clojure Slack上的几个人帮助我了解了这里发生的一切(谢谢!)。 compare-and-set!
使用identical?
(即Java参考相等)比较原子的旧值和新值。每次重新创建向量[x y]
时,我都会创建一个新对象,该对象与旧对象不identical?
。即使我不认为内部swap!
可以使任何事物发生变异,但从技术上讲,它是对的。