Struct Clojure结构嵌套在另一个结构中
是否可以在Clojure的结构中嵌套一个结构?考虑下面的代码:Struct Clojure结构嵌套在另一个结构中,struct,clojure,nested,Struct,Clojure,Nested,是否可以在Clojure的结构中嵌套一个结构?考虑下面的代码: (defstruct rect :height :width) (defstruct color-rect :color (struct rect)) (defn #^{:doc "Echoes the details of the rect passed to it"} echo-rect [r] (println (:color r)) (println (:height r)) (println (:width
(defstruct rect :height :width)
(defstruct color-rect :color (struct rect))
(defn
#^{:doc "Echoes the details of the rect passed to it"}
echo-rect
[r]
(println (:color r))
(println (:height r))
(println (:width r)))
(def first-rect (struct rect 1 2))
;(def c-rect1 (struct color-rect 249 first-rect)) ;form 1
;output "249 nil nil"
(def c-rect1 (struct color-rect 249 1 2)) ;form 2
;output "Too many arguments to struct constructor
(echo-rect c-rect1)
当然,这是一个人为的例子,但在某些情况下,我希望将大型数据结构分解为较小的子结构,以使代码更易于维护。如注释所示,如果我使用表单1,我会得到“249 nil nil”,但是如果使用表单2,我会得到“太多的参数到结构构造函数”
如果我以错误的方式处理这个问题,请告诉我应该做什么。搜索Clojure谷歌群对我来说没有任何帮助
编辑: 我想我的问题陈述没有我想象的那么清楚: 1.)是否可以在Clojure中将一个结构嵌套在另一个结构中?(从下面的判断是肯定的。) 2.)如果是,正确的语法是什么?(同样,从下面来看,似乎有几种方法可以做到这一点。) 3.)当一个结构嵌套在另一个结构中时,如何通过指定键获取值
我想我的示例代码并没有真正演示我要做的事情。我将此添加到这里,以便其他搜索此内容的人可以更轻松地找到此问题及其答案。我对clojure很陌生,所以我可能是错的。但我认为,你不能做这样的事情
(defstruct color-rect :color (struct rect))
就我所理解的clojure结构而言,这将创建一个结构(基本上是一个具有已知键的映射),它以某种方式将结构“rect”作为它的键之一
我的假设得到了一个观察结果的支持,即对(struct rect)的简单计算会产生
鉴于(struct color rect)的计算结果:
编辑:可以帮助您的是,结构不限于键,它们是用定义的。似乎你可以通过这样的方式完成你正在尝试的事情:
(def c-rect1 (struct-map color-rect :color 249 :height 1 :width 1 )) ;form 3
嵌套结构是可能的,有时也是可取的。然而,看起来您正在尝试做一些不同的事情:看起来您正在尝试使用结构类型的继承,而不是组合。也就是说,在表单2中,您正在创建一个包含一个rect的color rect,但您正在尝试构造一个实例,就像它是一个rect一样。表单1之所以有效,是因为您是从预先存在的rect构造c-rect1,这是使用组合的正确方法 在Clojure组上或仅仅在web上进行快速搜索,可以很好地描述组合和继承之间的区别。在Clojure中,组合或duck类型(再次查看Google)几乎总是比继承更受欢迎
编辑: 在回答您的问题#3时:如Brian Carper在其回答中所述,使用->提取嵌套结构中的数据的另一种方法是进入,以及其同级关联和更新: 例如:
(def cr {:rect {:height 1, :width 2}, :color :blue})
(get-in cr [:rect :width])
;; => 2
(assoc-in cr [:rect :height] 7)
;; => {:rect {:height 7, :width 2}, :color :blue}
(update-in cr [:rect :width] * 2)
;; => {:rect {:height 1, :width 4}, :color :blue}
(assoc-in cr [:a :new :deeply :nested :field] 123)
;; => {:a {:new {:deeply {:nested {:field 123}}}},
;; :rect {:height 1, :width 2}, :color :blue}
我同意其他海报中的观点,结构映射并不真正支持继承。但是,如果您只想创建一个使用另一个结构的键的新结构,这将起作用:
; Create the rect struct
(defstruct rect :height :width)
; Create the color-rect using all the keys from rect, with color added on
(def color-rect (apply create-struct (cons :color (keys (struct rect)))))
(defn create-color-rect
"A constructor function that takes a color and a rect, or a color height and width"
([c r] (apply struct (concat [color-rect c] (vals r))))
([c h w] (struct color-rect c h w)))
您不需要使用echo rect
函数,只需计算struct map实例即可查看其中的内容:
user=> (def first-rect (struct rect 1 2))
#'user/first-rect
user=> first-rect
{:height 1, :width 2}
user=> (create-color-rect 249 first-rect)
{:color 249, :height 1, :width 2}
user=> (create-color-rect 249 1 2)
{:color 249, :height 1, :width 2}
如果给一个结构一个要关联的键,则可以使它成为另一个结构的值。你可以按下面的方法做 (您可以通过
->
轻松访问任意嵌套的哈希/结构的核心,这是一种语法上的糖分。)
我意识到这是一个老问题,但我提出了以下宏观问题:
(defmacro extendstruct [n b & k]
`(def ~n
(apply create-struct
(clojure.set/union
(keys (struct ~b))
#{~@k}))))
这将允许您编写以下内容:
(defstruct rect :width :height)
(extendstruct color-rect rect :color)
测试:
(struct rect) ; {:width nil, :height nil}
(struct color-rect) ; {:color nil, :width nil, :height nil}
这就是你想要的吗
还可以对其进行修改,以便使用一组结构。或者甚至允许您使用其他结构定义作为键的名称,这些键会自动扩展为此类结构生成的键:
(defstructx one :a :b)
(defstructx two :c one :d)
(defstructx three :e two :f :g)
; three
(keys (struct three)) ; #{:e :c :a :b :d :f :g}
这是正确的:您正在使用一个空的rect结构作为color rect值之一的键。使用诸如:rect.Thank Paul之类的词会更有意义——这正是我想知道的。
(defstruct rect :width :height)
(extendstruct color-rect rect :color)
(struct rect) ; {:width nil, :height nil}
(struct color-rect) ; {:color nil, :width nil, :height nil}
(defstructx one :a :b)
(defstructx two :c one :d)
(defstructx three :e two :f :g)
; three
(keys (struct three)) ; #{:e :c :a :b :d :f :g}