[编辑:如何在网站上正确格式化代码?我尝试了,但无法解决这个问题,所以我只是将其作为markdown留了下来。]
您是否仍然考虑添加`update-keys`和`update-vals`的可变参数情况?在我发现我的用例不受支持后,我很惊讶,我认为我有一个相当有力的例子证明这很有必要。
我有一个这样的数据结构(以及稍后要使用的谓词)
```
(def data {:foo {0 {:bar [10 42 11 12]}
1 {:bar [20 21 42 22]}
,,, }})
(def my-special-pred (complement #{42}))
```
(注意 `(data :foo)` 中可以有任意多的项目;三个逗号应表示省略号。)
假设我想更新 `:foo 0 :bar` 的向量。这可以通过以下方式完成:
```
(update data :foo update 0 update :bar (partial filter my-special-pred))
```
在这种情况下,你也可以直接使用 `update-in`(你可能应该这样做)。但如果你想要对 `:foo` 映射中的所有值而不是仅 0 位置的值执行此操作呢?你应该能够只使用
```
(update data :foo update-vals update :bar (partial filter my-special-pred))
```
但是你不能,因为 `update-vals` 只接受两个参数。取而代之的是,你需要做的是
```
(update data :foo update-vals #(update % :bar (partial filter my-special-pred)))
```
这比最初看起来更不方便;由于匿名函数字面量不允许嵌套,你无法使用另一个(例如)对谓词。但是,使用可变参数的 `update-vals`,你可以这样做
```
(update data :foo update-vals update :bar (partial filter #(not= 0 (mod % 42))))
```
出于相同的原因,你无法轻松地使用多个 `update-vals` "层",像这样
```
(def data2 {0 {:top 200
:bottom 201
,,, }
1 {:left 300
:right 301
,,, }})
(update-vals data2 update-vals inc)
```
有各种方法可以解决这个问题,但到目前为止,最干净、最好的方法似乎就是只编写自己的`update-vals`函数,该函数封装了现有的一个函数
```
(defn update-vals [m f & args]
(clojure.core/update-vals m #(apply f % args)))
```
定义完后,这个注释中的所有示例都按预期工作。由于这是一个“添加变化”(它是现有功能的严格超集),因此它与向后兼容,并且应该(并且应该)包含在核心库中。
(另外,记录一下,`data2`示例是虚构的,但另一个示例的结构与我为自己的项目刚刚编写的实际代码相同,我将使用变长`update-vals`包装器。)