2009-02-16 72 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}