3

refs に 2 つのマップがあり、それらを 1 つのトランザクションで相互に関連付けたいと考えています。

私の関数は次のようになります。

(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ますか?

4

2 に答える 2

6

スタック オーバーフローは、REPL などで循環参照の 1 つを出力しようとするまで発生しません。

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

明らかに、このような循環参照オブジェクトを印刷することは問題になりますが、参照型のコンテンツのデフォルトの印刷を無効にすることに関するこの最近の質問と回答を参照してください

(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)
于 2014-08-21T18:06:49.683 に答える