2014-08-27 31 views
3

是否有任何方法可以在多方法中的多個方法之間重用解構?重複使用多方法的解構

(defmulti foo (fn [x] (:a x))) 
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e)) 
(defmethod foo :2 [a] "") 
(defmethod foo :3 [a] "") 

現在,這是一個簡單的例子,但是想象一下,我們有一個嵌套的地圖更加複雜的解構,我想用它在我所有的defmethods foo的。我會怎麼做?

+0

Nit-picking:根據[this](http://clojure.org/reader#The%20Reader--Reader%20forms),關鍵字應該以字母或*,+,!, - 開頭, _, 要麼 ?。 – Thumbnail 2014-08-27 13:34:32

回答

5

實際的解決方案是隻使用您需要的每個單獨方法的密鑰。關於解構的一個重要的事情是,你不必綁定你解構的集合中的每個值。假設傳遞給此多方法的每個映射都包含密鑰:a:e,但每種方法只需要一些這樣的密鑰。你可以做這樣的事情:

; note: a keyword can act as a function; :a here is equivalent to (fn [x] (:a x)) 
(defmulti foo :a) 
(defmethod foo :1 [{:keys [a b c d e]}] (str a b c d e)) 
(defmethod foo :2 [{:keys [b d]}] (str b d)) 
(defmethod foo :3 [{:keys [c e a]}] (str a c e)) 

如果你有一個複雜的嵌套結構,你想抓住特定的值,你可以離開了你不需要的鑰匙,或者根據你的使用情況,函數定義中的一個let綁定可能最終更易於閱讀。想起Steve Losh的Caves of Clojure - 在Clojure中從頭開始編寫一個roguelike文本冒險遊戲,他使用嵌套地圖來表示遊戲的狀態。最初,他寫的一些使用解構進入「比賽狀態」地圖內位的功能,例如:

(defmethod draw-ui :play [ui {{:keys [tiles]} :world :as game} screen] 
    ... 

但隨後later,他決定把這個代碼的可讀性通過了拉拆解成讓綁定:

(defmethod draw-ui :play [ui game screen] 
    (let [world (:world game) 
     tiles (:tiles world) 
     ... 

的一點是,如果你有一個深度嵌套結構的情況下想保持代碼的簡單(尤其是如果你正在寫幾個方法採取的是相同的結構作爲一個多重方法參數),你可能想要避免使用解構並只使用let綁定來抓取你想要的東西。 get-in是從嵌套集合中簡明獲取值的好工具。讓我們回到Clojure的例子的洞穴,如果史蒂夫只是需要的瓷磚,他可以做這樣的事情:

(defmethod draw-ui :play [ui game screen] 
    (let [tiles (get-in game [:world :tiles]) 
    ... 

就個人而言,我覺得更容易比{{:keys [tiles]} :world :as game}打亂函數的參數讀取。


編輯:

如果你真的想避免重複解構每個多方法,你希望每個方法都有相同的可用綁定,你可以寫一個宏:

(defmulti foo :a) 

(defmacro deffoomethod [dispatch-val & body] 
    `(defmethod foo ~dispatch-val [{:keys [~'a ~'b ~'c ~'d ~'e]}] 
    [email protected])) 

(deffoomethod 1 (str a b c d e)) 
(deffoomethod 2 (str b d)) 
(deffoomethod 3 (str a c e)) 

(foo {:a 1 :b 2 :c 3 :d 4 :e 5}) 
;=> "12345" 

(foo {:a 2 :b \h :d \i}) 
;=> "hi" 

(foo {:a 3 :b \x :c 0 :d \x :e 0}) 
;=> "300" 

我不會推薦這種方法,因爲它會打破宏觀衛生。任何使用此宏的人都必須記住,它將符號ae綁定到參數中的相應鍵,這可能會產生問題。

+0

Awsome!謝謝! – user3748315 2014-08-28 06:11:39

+0

@Dave - 寫得很好! – 2016-01-28 20:14:35