【问题标题】:two clojure map refs as elements of each other两个 clojure map refs 作为彼此的元素
【发布时间】:2014-08-21 17:38:14
【问题描述】:

我在 refs 中有两个映射,并希望在一个事务中将它们相互关联。

我的函数如下所示:

(defn assoc-two
  [one two]
  (let [newone (assoc @one :two two)
        newtwo (assoc @two :one one)]
    (ref-set one newone)
    (ref-set two newtwo)))

现在我像这样打电话给assoc-two

(dosync (assoc-two (ref {}) (ref {})))

此时我得到了 StackOverflowError。

我也试过这个:

(defn alter-two
  [one two]
  (alter one assoc :two two)
  (alter two assoc :one one))

如果one 有一个引用two 的条目(反之亦然)并且仍在一个事务中,是否可以这样做?

【问题讨论】:

    标签: clojure circular-reference refs


    【解决方案1】:

    在您尝试打印循环引用之一之前不会发生堆栈溢出,例如在 REPL。

    so.core=> (def a (ref {})) #'so.core/a so.core=> (def b (ref {})) #'so.core/b so.core=> (do (dosync (alter-two a b)) :success) :成功 so.core=> (= b (:two @a)) 真的 so.core=> (= a (:one @b)) 真的

    显然,像这样打印循环引用的对象会有问题,但请参阅this recent question and answer 关于禁用引用类型内容的默认打印

    (remove-method print-method clojure.lang.IDeref)
    
    (dosync (alter-two (ref {}) (ref {})))
    ;=> {:one #<Ref clojure.lang.Ref@7f1f91ac>} 
    ;   (prints the second ref without attempting to print its circular contents)
    

    【讨论】:

    • 哦,我可能已经猜到了。谢谢
    【解决方案2】:

    答案可以在下面的几篇文章中找到,这只是 REPL 试图打印你的递归结构。 您必须删除打印方法:

    (remove-method print-method clojure.lang.IDeref)
    

    或者添加一个处理你特定情况的打印方法,这个方法必须比常见的clojure.lang.IDeref更具体

    【讨论】:

      猜你喜欢
      • 2013-03-16
      • 1970-01-01
      • 2015-08-14
      • 1970-01-01
      • 2018-09-07
      • 1970-01-01
      • 2023-04-03
      • 2018-03-19
      • 1970-01-01
      相关资源
      最近更新 更多