4

直到现在,我一直认为你可以在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] ...这件事不起作用(或不应该)有什么特别的原因吗?

4

1 回答 1

5

如果您想要可变数量的参数,则缺少 &:

(defn foo [& [x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

Clojure 参数定义只有一种特殊情况,即&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 个强制参数,参数数量可变,而您拥有的 fn 有 1 个强制参数,参数数量可变。我正在做的只是解构var arg。

于 2014-10-12T22:30:32.390 回答