我的函数行为不同,具体取决于哪些关键字参数提供了值。对于这个问题,我想知道根据所提供的参数类型,行为略有不同的函数。
示例函数,用于递增列表的每个元素:
(defn inc-list [& {:keys [list-str list]}]
(let [prepared-list (if-not (nil? list) list (clojure.string/split list-str #","))]
(map inc prepared-list)))
制作一个多方法而不是测试参数类型是否有意义?我之前没有使用过多种方法,也不确定正确的时间使用它们。如果这是一个好主意,下面的例子会有意义吗?
示例:
(defn inc-coll [col] (map inc col))
(defmulti inc-list class)
(defmethod inc-list ::collection [col] (inc-col col))
(defmethod inc-list String [list-str]
(inc-col
(map #(Integer/parseInt %)
(clojure.string/split list-str #",")))
答案 0 :(得分:5)
首先要做的事情是:(map 'inc x)
将x
中的每个项目视为关联集合,并查找按键'inc
索引的值。
user> (map 'inc '[{inc 0} {inc 1} {inc 2}])
(0 1 2)
你可能想要inc
而不是
user> (map inc [0 1 2])
(1 2 3)
接下来,我们尝试inc
一个字符串,string/split
的args乱序,以及一些拼写错误。
如果您在class
上定义多个调度,那么方法应该由类参数化,而不是关键字占位符。我更改了多功能,因此它适用于任何Clojure知道如何作为seq处理的东西。此外,作为一点bikeshed,最好使用type
,这为区分class
未提供的Clojure代码中的输入提供了一些区别:
user> (type (with-meta {:a 0 :b 1} {:type "foo"}))
"foo"
全部放在一起:
user> (defn inc-coll [col] (map inc col))
#'user/inc-coll
user> (defmulti inc-list type)
nil
user> (defmethod inc-list String [list-str]
(inc-coll (map #(Integer/parseInt %) (clojure.string/split list-str #","))))
#<MultiFn clojure.lang.MultiFn@6507d1de>
user> (inc-list "1,10,11")
(2 11 12)
user> (defmethod inc-list clojure.lang.Seqable [col] (inc-coll (seq col)))
#<MultiFn clojure.lang.MultiFn@6507d1de>
user> (inc-list [1 2 3])
(2 3 4)
答案 1 :(得分:2)
你的第一个例子是一个名为dispatching on type的技术的混淆应用程序。它是混淆的,因为在消息传递样式中,调用者必须将类型传递给您的函数。
因为在每种情况下你只使用其中一个关键字args,你也可以将它定义为:
(defn inc-list
[m l]
(->> (case m ;; message dispatch
:list l
:list-str (map #(edn/read-string %) (str/split #",")) l)
(map inc)))
呼叫者可以免于通过m:
(defn inc-list
[l]
(->> (cond (string? l) (map ...)
:else l)
(map inc)))
这种技术的主要缺点是,当向代码库引入新类型时,必须修改操作过程代码。
在Clojure中,它通常被多态构造protocols取代,e。 G:
(defprotocol IncableList
(inc-list [this]))
可以在任何类型上实施,例如克。
(extend-type clojure.lang.Seqable
IncableList
(inc-list [this] (map inc this)))
(extend-type String
IncableList
(inc-list [this] (map #(inc ...) this)))
Multimethods允许相同的功能,并通过将调度机制与操作过程分离并提供数据导向编程的可加性,为消息传递和调度类型提供额外的灵活性。但它们的执行速度比协议慢。
在您的示例中,目的是根据类型进行调度,因此您不需要多方法和协议是适当的技术。