是否可以将结构嵌套在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.。当你有一个嵌套在另一个结构中的结构时,如何通过指定的键获取值?
我想我的示例代码并没有真正展示我想要做的很好。我在这里添加这个,以便其他人搜索这个可能更容易找到这个问题及其答案。
答案 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}