如何将可变参数函数的其余参数传递给另一个函数?

How to pass the rest args of a variadic function to another function?

我想编写一个函数,它只用新值更新映射中的向量,但可以接受任意数量的参数,但至少有一个。

示例如下:

(defn my-update [what item & items]
  (update what :desired-key conj item items))

不幸的是,这不起作用。尽管 update 确实有一个包含多个值的签名(如 [m k f x y]),但 my-update 的所有剩余参数将被连接成一个序列,该序列将传递给 conj 作为一个参数。

相反,在匿名函数中用 apply 包装 conj 确实有效,但看起来不太优雅:

(defn my-update [what item & items]
  (update what :desired-key #(apply conj % item items))

my-update这样的函数的惯用写法是什么?

您现有的解决方案还不错。一个小的改进是使用 into 函数,它在内部使用 conj 将两个序列连接在一起:

(defn my-update [what & items]
  (update what :a into items))

结果

(my-update {:a [1]} 2 3 4) => {:a [1 2 3 4]}

另一种方法是将匿名函数提取到命名函数中:

(defn append-to-seq
  [seq item items]
  (-> (vec seq)  ; ensure it is a vector so conj adds to the end, not beginning
    (conj item)
    (into items)))

(defn my-update [what item & items]
  (update what :a append-to-seq item items))


您可以在 update 之前简单地插入 apply。这将使用后面的参数调用函数 update,除了最后一个参数应该是一个序列,其元素成为调用中的其余参数:

(defn my-update [what item & items]
  (apply update what :desired-key conj item items))

(my-update {:desired-key [0]} 1 2 3 4)
;; => {:desired-key [0 1 2 3 4]}

(my-update {:desired-key [0]})
;; Exception: Wrong number of args (1) passed to: my-update

这样,您可以保留函数参数列表 [what item & items],清楚地表明至少需要提供一项。

一般来说,调用 (apply f a b c ... [x y z ...]) 的计算结果与 (f a b c ... x y z ...) 相同。