Clojure是否有命名参数?如果是这样,请您提供一个小例子吗?
答案 0 :(得分:114)
在Clojure 1.2中,您可以像解构地图一样对rest
参数进行解构。这意味着您可以执行命名的非位置关键字参数。这是一个例子:
user> (defn blah [& {:keys [key1 key2 key3]}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there" :key3 10)
"Hai there10"
user> (blah :key1 "Hai" :key2 " there")
"Hai there"
user> (defn blah [& {:keys [key1 key2 key3] :as everything}] everything)
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
{:key2 " there", :key1 "Hai"}
在解构Clojure地图时可以做的任何事情可以在函数的参数列表中完成,如上所示。包括使用:或定义参数的默认值,如下所示:
user> (defn blah [& {:keys [key1 key2 key3] :or {key3 10}}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"
但这是在Clojure 1.2中。或者,在旧版本中,您可以这样做来模拟同样的事情:
user> (defn blah [& rest] (let [{:keys [key1 key2 key3] :or {key3 10}} (apply hash-map rest)] (str key1 key2 key3)))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"
并且通常以相同的方式工作。
您还可以在关键字参数之前使用位置参数:
user> (defn blah [x y & {:keys [key1 key2 key3] :or {key3 10}}] (str x y key1 key2 key3))
#'user/blah
user> (blah "x" "Y" :key1 "Hai" :key2 " there")
"xYHai there10"
这些不是可选的,必须提供。
您实际上可以像对待任何Clojure集合一样对rest
参数进行解构。
user> (defn blah [& [one two & more]] (str one two "and the rest: " more))
#'user/blah
user> (blah 1 2 "ressssssst")
"12and the rest: (\"ressssssst\")"
即使在Clojure 1.1中你也可以做到这一点。关键字参数的地图式解构只有1.2。但
答案 1 :(得分:33)
除了Raynes的优秀答案外,还有a macro in clojure-contrib让生活更轻松:
user=> (use '[clojure.contrib.def :only [defnk]]) nil user=> (defnk foo [a b :c 8 :d 9] [a b c d]) #'user/foo user=> (foo 1 2) [1 2 8 9] user=> (foo 1 2 3) java.lang.IllegalArgumentException: No value supplied for key: 3 (NO_SOURCE_FILE:0) user=> (foo 1 2 :c 3) [1 2 3 9]
答案 2 :(得分:1)
从Clojure 1.8版开始,关键字支持似乎仍然有点 meh 。
您可以这样指定关键字参数:
(defn myfn1
"Specifying keyword arguments without default values"
[& {:keys [arg1 arg2]}]
(list arg1 arg2))
调用示例:
(myfn1 :arg1 23 :arg2 45) --> evaluates to (23 45)
(myfn1 :arg1 22) --> evaluates to (22 nil)
如果要为这些关键字参数指定默认值:
(defn myfn2
"Another version, this time with default values specified"
[& {:keys [arg1 arg2] :or {arg1 45 arg2 55}}]
(list arg1 arg2))
这在第二种情况下可以完成预期的事情:
(myfn2 :arg1 22) --> evaluates to (22 55)
每种语言的每个部分都有优点和缺点,但是为了比较起见,这是您在Common Lisp中做相同事情的方式:
(defun myfn3
(&key arg1 arg2)
"Look Ma, keyword args!"
(list arg1 arg2))
(defun myfn4
(&key (arg1 45) (arg2 55))
"Once again, with default values"
(list arg1 arg2))
答案 3 :(得分:0)
您是否意味着命名参数?这些不是直接可用的,但如果您愿意,可以use this vectors approach,这可能会给您你想要的东西。
At RosettaCode对于如何使用解构进行更深入的解释。