考虑具有以下签名的函数:
(defn make-widget [& {:keys [x y] :or {x 10 y 20}}]
...)
将映射传递给函数的最佳方式是什么,例如:
(make-widget {:x 100})
或
(make-widget {:y 200 :x 0})
我目前想到的是通过
vec
、flatten
和 apply
例如:
(apply make-widget (flatten (vec ({:x 100}))
我坚信有更好的方法可以做到这一点。可以考虑一下吗?
我也想不出更优雅的方式,尽管在我看来应该有一种(比如
apply
的特定于地图的变体)。
使用
flatten
除了不够优雅之外还有其他问题。如果你的地图的值是集合,flatten
也会递归地处理这些,所以事情可能会完全混淆。这个替代方案避免了这个问题:
(apply make-widget (apply concat {:x 100}))
还有一个已知的(至少不是我发明的)函数“mapply”:
(defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))
可以这样应用
(mapply your-function {:your "map"})
至于为什么 Clojure 核心中缺少这种特定于语言的功能,并且实现得更加原生和优雅,没有人能给我明确的答案。
更新
在我花了很多时间在 Clojure 中编程之后,我个人倾向于避免创建接受
{}
作为可变参数的函数。尽管乍一看这似乎很有吸引力,但实际上经验证明,出于多种原因,通过明确的 {}
总是更好。
您可以使用:
(apply make-widget (mapcat identity {:x 200 :y 0}))
对于 2021 年之后阅读本文的任何人,从 Clojure 1.11 开始,您可以直接将映射传递给函数(按照最初问题所希望的方式)。无需做任何额外的工作!
(defn make-widget [& {:keys [x y] :or {x 10 y 20}}]
(prn x y))
(make-widget :x 1) ; => 1 20
(make-widget {:x 100}) ; => 100 20
(make-widget {:y 200 :x 0}) ; => 0 200
有关更多详细信息,请参阅原始公告:https://clojure.org/news/2021/03/18/apis-serving-people-and-programs