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



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

示例:

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

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

相反,将conjapply包装在一个匿名函数中确实可以工作,但看起来不那么优雅:

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

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

您只需在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 ...)的计算结果相同。

您现有的解决方案还不错。一个小小的改进是使用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))

相关内容

  • 没有找到相关文章

最新更新