如何表示两个records/maps之间的父子关系?
How to represent parent-child relationship between two records/maps?
我试图在 Clojure/Script 中表示 gui 元素。问题是元素是嵌套的,需要相互通信。我想互相传递引用,但似乎我不能像我天真地想的那样只是互相传递引用。
我试过的代码
(defrecord Element [position size parent children state type value])
(def parent (atom (Element. ...)))
(def child (atom (Element. ...)))
(assoc @parent :child child)
(assoc @child :parent parent)
这行不通。
对于此类问题,Clojure 中惯用的解决方案是什么?
更新:相互引用似乎不起作用:
(defrecord Element [position size parent children state type value])
(def parent (atom (Element. {:x 0 :y 0} {:width 1600 :height 900} nil nil :collapsed :container nil)))
(def child (atom (Element. {:x 5 :y 5} {:width 100 :height 100} nil nil :collapsed :container nil)))
(swap! parent assoc :child child)
(swap! child assoc :parent parent)
#object[InternalError InternalError: too much recursion]
cljs.core.PersistentArrayMap.prototype.cljs$core$ILookup$_lookup$arity (jar
:file:/C:/Users/user/.m2/repository/org/clojure/clojurescript/1.10.520/clojuresc
ript-1.10.520.jar!/cljs/core.cljs:6811:10)
也许在 Clojure 中你不做相互引用?
您 assoc
将 parent 转换为 child,但随后丢弃了新的 Element
。您需要使用 reset!
或 swap!
:
设置原子中的值
(swap! parent assoc :child child) ; Equivalent to (swap! parent #(assoc % :child child))
(swap! child assoc :parent parent)
swap!
is similar to update
,但它替换了 atom
.
中的值
另请注意,您为字段指定了名称 children
,但在您的示例中,您使用 :child
引用它。 children
建议使用多个 children,所以我将其更改为以向量开始而不是 nil
,然后是 conj
。我还会创建一个 new-element
助手:
(defrecord Element [position size parent children state type value])
(defn new-element [position size]
(->Element position size nil [] :collapsed :container nil))
(def parent (atom (new-element {:x 0 :y 0} {:width 1600 :height 900})))
(def child (atom (new-element {:x 5 :y 5} {:width 100 :height 100})))
(swap! parent update :children conj child)
(swap! child assoc :parent parent)
为了解决您遇到的错误,它在 Clojure.
中对我来说运行良好
如果我在上面的代码运行后打印 parent
和 child
,我会得到一个无限的输出,因为要打印 parent 你需要打印 child,要打印 child,您需要打印 parent... 不过它对我仍然有效。
确保不会出现错误,因为您正在尝试在 REPL 中打印结构。
这也可能是 Clojurescript 的限制。很遗憾,我无法回答这个问题,因为我不熟悉 Cljs。
如果这最终没有帮助,我会删除我的答案。
我还会注意到嵌套原子不是一个好主意。 atom
s 是真正可变的容器来容纳不可变的 objects。拥有一个 ID 系统并让每个 parent/child 持有一个数字 ID 到它的 child/parent 可能会更干净。然后你的整个程序只有一个原子。原子可以保存 ID-> 元素的映射,以便于查找。
我试图在 Clojure/Script 中表示 gui 元素。问题是元素是嵌套的,需要相互通信。我想互相传递引用,但似乎我不能像我天真地想的那样只是互相传递引用。
我试过的代码
(defrecord Element [position size parent children state type value])
(def parent (atom (Element. ...)))
(def child (atom (Element. ...)))
(assoc @parent :child child)
(assoc @child :parent parent)
这行不通。
对于此类问题,Clojure 中惯用的解决方案是什么?
更新:相互引用似乎不起作用:
(defrecord Element [position size parent children state type value])
(def parent (atom (Element. {:x 0 :y 0} {:width 1600 :height 900} nil nil :collapsed :container nil)))
(def child (atom (Element. {:x 5 :y 5} {:width 100 :height 100} nil nil :collapsed :container nil)))
(swap! parent assoc :child child)
(swap! child assoc :parent parent)
#object[InternalError InternalError: too much recursion]
cljs.core.PersistentArrayMap.prototype.cljs$core$ILookup$_lookup$arity (jar
:file:/C:/Users/user/.m2/repository/org/clojure/clojurescript/1.10.520/clojuresc
ript-1.10.520.jar!/cljs/core.cljs:6811:10)
也许在 Clojure 中你不做相互引用?
您 assoc
将 parent 转换为 child,但随后丢弃了新的 Element
。您需要使用 reset!
或 swap!
:
(swap! parent assoc :child child) ; Equivalent to (swap! parent #(assoc % :child child))
(swap! child assoc :parent parent)
swap!
is similar to update
,但它替换了 atom
.
另请注意,您为字段指定了名称 children
,但在您的示例中,您使用 :child
引用它。 children
建议使用多个 children,所以我将其更改为以向量开始而不是 nil
,然后是 conj
。我还会创建一个 new-element
助手:
(defrecord Element [position size parent children state type value])
(defn new-element [position size]
(->Element position size nil [] :collapsed :container nil))
(def parent (atom (new-element {:x 0 :y 0} {:width 1600 :height 900})))
(def child (atom (new-element {:x 5 :y 5} {:width 100 :height 100})))
(swap! parent update :children conj child)
(swap! child assoc :parent parent)
为了解决您遇到的错误,它在 Clojure.
中对我来说运行良好如果我在上面的代码运行后打印 parent
和 child
,我会得到一个无限的输出,因为要打印 parent 你需要打印 child,要打印 child,您需要打印 parent... 不过它对我仍然有效。
确保不会出现错误,因为您正在尝试在 REPL 中打印结构。
这也可能是 Clojurescript 的限制。很遗憾,我无法回答这个问题,因为我不熟悉 Cljs。
如果这最终没有帮助,我会删除我的答案。
我还会注意到嵌套原子不是一个好主意。 atom
s 是真正可变的容器来容纳不可变的 objects。拥有一个 ID 系统并让每个 parent/child 持有一个数字 ID 到它的 child/parent 可能会更干净。然后你的整个程序只有一个原子。原子可以保存 ID-> 元素的映射,以便于查找。