到目前为止,我一直认为你可以在let
绑定中做任何事情,你可以在defn
形式的参数向量中做。
然而,我只是注意到了这一点 - 如果我使用let
绑定执行此操作,则可行:
(let [[x & more :as full-list] (range 10)]
(println "x:" x)
(println "more:" more)
(println "full list:" full-list))
; x: 0
; more: (1 2 3 4 5 6 7 8 9)
; full list: (0 1 2 3 4 5 6 7 8 9)
但如果我尝试将其拉入函数中,我会得到一个例外:
(defn foo [x & more :as full-list]
(println "x:" x)
(println "more:" more)
(println "full list:" full-list))
; CompilerException java.lang.RuntimeException: Unexpected parameter, compiling:(/tmp/form-init615613631940782255.clj:1:1)
值得注意的是,这有效:
(defn foo [[x & more :as full-list]]
(println "x:" x)
(println "more:" more)
(println "full list:" full-list))
但是我必须将论证作为集合传递,即(foo [1 2 3])
。
是否可以定义一个带有可变数量参数的函数,并将整个参数组绑定到局部变量,而无需在内部使用let
绑定?让我感到奇怪的是,你不能做到(defn foo [x & more :as full-list] ...
是否有一个特殊的原因导致它不能(或不应该)起作用?
答案 0 :(得分:4)
如果你想要一个可变数量的args,你就错过了&:
(defn foo [& [x & more :as full-list]]
(println "x:" x)
(println "more:" more)
(println "full list:" full-list))
Clojure param定义只有一个特殊情况,即&
char,表示可变数量的参数。其余的都是简单的命名参数。
现在可以使用map或list语法对每个简单参数进行解构。例如:
(defn foo [ x y ] ...)
可以像以下一样进行解构:
(defn foo [[x1 x2 & x-more :as x] {:keys [y1 y2 y3]}] ...)
所以我们说我们期望第一个参数是至少2个元素的列表,第二个参数是带有一些键的映射。请注意,这仍然是两个参数的fn,并且Clojure不会强制执行x实际上至少有两个元素。如果x是空列表,则x1和x2将为nil。
回到你的问题,如果你看看我的答案,你会看到我的fn有0个强制参数,参数数量可变,而你拥有的参数有1个强制参数和一个可变数量的参数。我正在做的只是解构var arg。