在Clojure中解构函数参数

时间:2014-07-16 08:19:21

标签: clojure

我在Chas Emerick等人的 Clojure Programming 中运行了一个例子:

(defn make-user
  [& [uid]]
  {:user-id (or uid (str (java.util.UUID/randomUUID)))})

输出:

=> (make-user" T-800")

{:user-id " T-800" }

现在我删除第2行中uid周围的方括号:

(defn make-user
  [& uid]
  {:user-id (or uid (str (java.util.UUID/randomUUID)))})

评估结果变为:

=> (make-user" T-800")

{:user-id (" T-800")}

如何理解这种差异?

2 个答案:

答案 0 :(得分:3)

[&安培; uid]:

  • &表示将所有参数放在一起作为名为uid的列表。
  • 所以,uid这里是类型列表

[&安培; [uid]]:

  • 将所有参数组合为[uid],这是一个列表(不是因为[],而是在&之后)。
  • 此外,通过抓取第一个元素uid
  • 来对此列表进行解构
  • 所以uid这里不是一个列表,只是一个元素。

答案 1 :(得分:3)

在参数声明中,将参数放在&旁边会导致它们被包装到列表中。

(defn return [x y & more]
  [x y more])

(return 1 2 3 4 5 6)
;=> [1 2 (3 4 5 6)]

这种包装对于操作函数中未确定数量的args非常有用:

(defn plus [& more] (apply + more))

(plus 3 4)
;=> 7

(plus 3 4 5 6)
;=> 18

但是如果我们知道只有一个元素作为可选参数并希望直接访问它,我们可以使用first来提取它:

(defn make-user-1 [& uid] {:user-id (first uid)})
(make-user-1 "T-800")
;=> {:user-id "T-800"}

或者,我们可以通过使用destructuring来解开参数元素!

(defn make-user-2 [& [uid]] {:user-id uid})
(make-user-2 "T-800")
;=> {:user-id "T-800"}

所以,这里有一些arg声明及其给定的输出:

(defn f [arg]     arg) ;=> arg
(defn f [& arg]   arg) ;=> (arg)
(defn f [& [arg]] arg) ;=> arg

你在arg声明中包装args的次数越多,在体内解包的次数就越多。