Clojure惯用的get-and-set函数

3

在Clojure中,有没有一种更符合惯用法/易读的写法来编写获取和设置函数呢?

(def the-ref (ref {}))

(defn get-and-set [new-value]
  (dosync
    (let [old-value @the-ref]
     (do
       (ref-set the-ref new-value)
       old-value))))
1个回答

2

对于简单情况,我倾向于直接使用这个操作,而不是将其包装在函数中:

hello.core> (dosync (some-work @the-ref) (ref-set the-ref 5))
5

在这种情况下,dosync通常作为您要查找的包装器。在dosync内部,这是非常重要的,因为dosync与其他事务很好地组合,并使事务的边界可见。如果您处于包装函数可以完全封装对ref的所有引用的位置,那么refs可能不是最好的工具。
引用的典型用法可能更像这样:
(dosync (some-work @the-ref @the-other-ref) (ref-set the-ref @the-other-ref))

需要包装它的情况很少,因为当引用被使用时,它们通常是以多个引用组的形式使用的,因为问题需要协调更改。在只有一个值的情况下,原子更为常见。


get-and-set的原因是我想对当前ref上的值进行批处理。该ref实际上是一组ref的映射,多个线程同时更新。由于批处理涉及一些io操作,我认为需要在事务之外进行,因此需要以原子方式获取ref的当前值并重置它。 - DanLebrero
在ref中的任何事务都将成为一个大事务的一部分,因为dosync会吸收内部事务。在refs中让副作用和阻塞操作正常工作的官方方法是将它们从ref发送到代理。Refs保证仅发送一次,并且仅使用实际提交的结果发送。如果事务中止,则不会发送消息。 - Arthur Ulfeldt
原子或代理可以使您在这个问题上的生活变得更轻松一些。 - Arthur Ulfeldt
Arthur,将批处理发送给代理确实是一个非常好的主意。非常感谢! - DanLebrero

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