2009-02-16 99 views
6

是否可以在Clojure中的结构中嵌套结构?请看下面的代码: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无零”,但如果我做了表格2,我会得到“结构构造函数太多的参数”。

如果我以错误的方式处理这个问题,请告诉我我该怎么做。搜索Clojure谷歌组对我来说没有任何东西。


编辑:

我想我是不是我的问题的声明明确的,因为我以为我是:

1)是否有可能一个嵌套结构内另一个Clojure的? (从下面判断,这是肯定的。)

2.)如果是这样,那么正确的语法是什么? (再次,从下面判断,看起来好像有几种方法可以做到这一点。)

3.)当你有一个嵌套在另一个结构中的结构体时,如何通过指定的键获取值?

我想我的示例代码并没有真正证明我试图做得很好。我在这里添加这个,以便其他人可以更容易地找到这个问题和答案。

回答

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功能,你可以简单地评估结构图实例,看看有什么在它:

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} 
+0

谢谢保罗 - 这正是我想知道的。 – 2009-02-17 22:38:24

1

我对clojure真的很陌生,所以我可能是错的。但我认为,你不能这样做

(defstruct color-rect :color (struct rect)) 

据我了解Clojure的-结构,这将创建一个结构(基本上是已知键地图),有莫名其妙的结构“矩形”作为其中一个关键。

我的假设是由(结构RECT)的一个简单的评价产生

{:height nil, :width nil} 

鉴于对(结构色-RECT)收益率的评估观察的支持:

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

编辑:什么可以帮助你的事实是,结构不限于密钥,它们是用定义的。看起来好像你可以完成,你试图通过这样的东西:

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

这是正确的:您使用的是空的矩形结构作为一个重点颜色矩形的值。使用类似rect的东西会更有意义。 – 2009-02-17 00:06:27

6

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

快速搜索Clojure小组或者只是在网络上一般应该引导您很好地描述组合和继承之间的区别。在Clojure中,组合或鸭子式(再次参见Google)几乎总是优先于继承。


编辑:

在回答你的问题#3:使用一个选择 - >提取嵌套结构数据,布赖恩·卡珀在他的回答中描述,是获得式,沿其兄弟姐妹assoc命令,并更新时间:

例如:

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

如果你给它一个关联的关键字,你可以使一个结构成为另一个结构的值。你可以这样做,如下所示。

(你可以很容易地通过->访问任意嵌套哈希/结构的胆量,因为有点语法糖。)

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

我意识到这是一个老问题了,但我想出了下面的宏:

(defmacro extendstruct [n b & k] 
    `(def ~n 
    (apply create-struct 
     (clojure.set/union 
     (keys (struct ~b)) 
     #{[email protected]})))) 

这将允许你这样写:

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