我正在尝试在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$2 (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
赋予孩子的父母,但随后扔掉了新的Element
。您需要使用reset!
或swap!
在原子中设置值:
(swap! parent assoc :child child) ; Equivalent to (swap! parent #(assoc % :child child))
(swap! child assoc :parent parent)
[swap!
与swap!
相似,但是它替换了update
中保存的值。
[另外请注意,您给字段指定了update
,但是在您的示例中,您使用的是atom
。虽然children
建议有多个孩子,所以我将其更改为矢量而不是:child
,然后是children
。我还要创建一个nil
助手:
conj
为了解决您遇到的错误,它在Clojure中对我来说运行正常。
如果在上面的代码运行后打印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)
,则会得到无限输出,因为要打印父级,您需要打印子级,而要打印子级,则需要打印父级...它仍然对我有用。
请确保不会发生此错误,因为您正尝试在REPL中打印出该结构。
这也可能是Clojurescript的局限性。不幸的是,由于我不熟悉Cljs,我无法回答。
如果最终没有帮助,我将删除答案。
我还将注意,嵌套原子不是一个好主意。 parent
实际上是可变的容器,用于保存不可变的对象。拥有一个ID系统,让每个父母/孩子为其孩子/父母持有一个数字ID,可能会更清洁。然后,整个程序只有一个原子。原子可以保存ID-> element的映射以便于查找。