2014-08-27 30 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