Clojure关键字参数

53
在Common Lisp中,您可以这样做:
(defun foo (bar &key baz quux)
  (list bar baz quux))

(foo 1 :quux 3 :baz 2) ; => (1 2 3)

Clojure没有关键字参数。其中一种替代方案是:

(defn foo [bar {:keys [baz quux]}] 
  (list bar baz quux))

(foo 1 {:quux 3 :baz 2}) ; => (1 2 3)

要在编写和阅读中省去太多的嵌套括号。同时,它需要传递一个显式哈希映射作为参数,而不是一个平面列表。

什么是最符合Clojure惯用法的关键字参数的等效方式,而不会看起来像有人引爆了一个标点符号炸弹?


3
自从这个问题最后活跃以来,Clojure 添加了关键字解构绑定(keyword destructuring binding)功能。我已经提供了一个答案来表明这一点。 - Alex Stoddard
1
@Brian,你应该考虑更新接受的答案。 - Brad Koch
3个回答

101
为了更新这个Clojure 1.2的答案,现在使用完整的关键字参数支持,并提供解构绑定地图形式的默认值。
user> (defn foo [bar &{ :keys [baz quux] 
                        :or {baz "baz_default" quux "quux_default"}}]
         (list bar baz quux))
#'user/foo

user> (foo 1 :quux 3)
(1 "baz_default" 3)

8
我认为这应该被推广为答案? - john2x

39

在Clojure中模拟关键字参数的一个简单方法是使用rest参数上的hash-map,像这样:

> (defn kwtest [x & e] (:foo (apply hash-map e)))
#'user/kwtest
> (kwtest 12 :bar "ignored" :foo "returned")
"returned"

Rich Hickey在clojure google group的这条信息中提供了一个宏,可以给你提供关键字参数。对应的帖子包含关于为什么Clojure不支持关键字参数的信息。基本上是为了避免运行时开销。Rich在这个消息中解释了我展示的方法。


请参考Alex Stoddard的回答,Clojure已经添加了对关键字参数的支持。 - Brad Koch

9
< p>最近增加到clojure.contrib.def中的是defnk宏,它使得可以使用关键字参数定义函数(请参见这里)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接