Clojure 应用映射和关键字参数销毁

问题描述 投票:0回答:4

考虑具有以下签名的函数:

(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}))

我坚信有更好的方法可以做到这一点。可以考虑一下吗?

dictionary clojure keyword-argument destruction
4个回答
11
投票

我也想不出更优雅的方式,尽管在我看来应该有一种(比如

apply
的特定于地图的变体)。

使用

flatten
除了不够优雅之外还有其他问题。如果你的地图的值是集合,
flatten
也会递归地处理这些,所以事情可能会完全混淆。这个替代方案避免了这个问题:

(apply make-widget (apply concat {:x 100}))

8
投票

还有一个已知的(至少不是我发明的)函数“mapply”:

(defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))

可以这样应用

(mapply your-function {:your "map"})

至于为什么 Clojure 核心中缺少这种特定于语言的功能,并且实现得更加原生和优雅,没有人能给我明确的答案。

更新

在我花了很多时间在 Clojure 中编程之后,我个人倾向于避免创建接受

{}
作为可变参数的函数。尽管乍一看这似乎很有吸引力,但实际上经验证明,出于多种原因,通过明确的
{}
总是更好。


7
投票

您可以使用:

(apply make-widget (mapcat identity {:x 200 :y 0}))

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

© www.soinside.com 2019 - 2024. All rights reserved.