Struct 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

是否可以在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 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}