Clojure - 命名参数

one*_*one 77 clojure

Clojure是否有命名参数?如果是这样,请您提供一个小例子吗?

Ray*_*yne 117

在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"}
Run Code Online (Sandbox Code Playgroud)

在解构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"
Run Code Online (Sandbox Code Playgroud)

但这是在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"
Run Code Online (Sandbox Code Playgroud)

并且通常以相同的方式工作.

并且您还可以在关键字参数之前使用位置参数:

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"
Run Code Online (Sandbox Code Playgroud)

这些不是可选的,必须提供.

你可以rest像任何Clojure集合一样对论证进行解构.

user> (defn blah [& [one two & more]] (str one two "and the rest: " more))
#'user/blah
user> (blah 1 2 "ressssssst")
"12and the rest: (\"ressssssst\")"
Run Code Online (Sandbox Code Playgroud)

你甚至可以在Clojure 1.1中做到这一点.关键字参数的地图样式解构只有1.2.


Ale*_*art 33

除了Raynes的优秀答案之外,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]

  • 我忘了提到那个!我全都陷入了展示Clojure可以破坏结构的万种方式的过程中.:p (6认同)
  • @Lstor:在[棱柱/管道]中查看[defnk](https://github.com/prismatic/plumbing/blob/7ae0e85e4921325b3c41ef035c798c29563736dd/src/plumbing/core.cljx#L470)(https://github.com/棱光/管道) (2认同)

aga*_*gam 7

从 Clojure 1.8 版开始,关键字支持似乎仍然有点乏味

您可以像这样指定关键字参数:

(defn myfn1
  "Specifying keyword arguments without default values"
  [& {:keys [arg1 arg2]}]
  (list arg1 arg2))
Run Code Online (Sandbox Code Playgroud)

调用示例:

(myfn1 :arg1 23 :arg2 45)  --> evaluates to (23 45)
(myfn1 :arg1 22)           --> evaluates to (22 nil)
Run Code Online (Sandbox Code Playgroud)

如果您想为这些关键字参数指定默认值:

(defn myfn2
  "Another version, this time with default values specified"
  [& {:keys [arg1 arg2] :or {arg1 45 arg2 55}}]
  (list arg1 arg2))
Run Code Online (Sandbox Code Playgroud)

这在第二种情况下完成了预期的事情:

(myfn2 :arg1 22)           --> evaluates to (22 55)
Run Code Online (Sandbox Code Playgroud)

每种语言的每个部分都有优点和缺点,但为了比较,这就是你在 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))
Run Code Online (Sandbox Code Playgroud)