嵌套在另一个结构中的Clojure结构

时间:2009-02-16 23:23:33

标签: 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 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.。当你有一个嵌套在另一个结构中的结构时,如何通过指定的键获取值?

我想我的示例代码并没有真正展示我想要做的很好。我在这里添加这个,以便其他人搜索这个可能更容易找到这个问题及其答案。

5 个答案:

答案 0 :(得分:7)

我同意其他海报的结构图并不真正支持继承。但是,如果您只想创建一个使用另一个键的新结构,这将起作用:

; 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}

答案 1 :(得分:6)

嵌套结构是可能的,有时也是可取的。但是,看起来你正在尝试做一些不同的事情:看起来你正在尝试使用结构类型的继承而不是组合。也就是说,在表单2中,您正在创建一个包含一个矩形的颜色矩形,但您正在尝试构建一个实例,就好像它 一个矩形一样。表单1的工作原理是因为你从一个预先存在的rect构造c-rect1,这是使用组合的正确方法。

快速搜索Clojure组或仅在网络上进行快速搜索,可以让您对组合和继承之间的区别有一个很好的描述。在Clojure中,组合或鸭子打字(再次参见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}

答案 2 :(得分:6)

如果给它一个与之关联的键,则可以使struct成为另一个struct的值。你可以这样做。

(你可以通过->轻松访问任意嵌套的哈希/结构的内容,作为一些语法糖。)

(defstruct rect :height :width)
(defstruct color-rect :rect :color)

(def cr (struct color-rect (struct rect 1 2) :blue))
;; => {:rect {:height 1, :width 2}, :color :blue}

(:color cr)           ;; => :blue
(:width (:rect cr))   ;; => 2
(-> cr :color)        ;; => :blue
(-> cr :rect :width)  ;; => 2

答案 3 :(得分:1)

我对clojure很新,所以我可能错了。但我想,你不能做像

这样的事情
(defstruct color-rect :color (struct rect))

据我了解clojure-structs,这会创建一个struct(基本上是一个带有已知键的映射),它以某种方式将struct'rect'作为其中一个键。

我的假设得到了(struct rect)简单评估

的观察结果的支持
{:height nil, :width nil}

而(struct color-rect)的评估产生:

{:color nil, {:height nil, :width nil} nil}

编辑:有什么可以帮助你的事实是,结构不仅限于键,它们是用它们定义的。看起来好像你可以完成,你正在通过这样的事情尝试:

(def c-rect1 (struct-map color-rect :color 249 :height 1 :width 1 )) ;form 3

答案 4 :(得分:1)

我现在意识到这是一个老问题,但我提出了以下宏:

(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}