[编辑:如何在网站上正确格式化代码?我试了,但没能搞明白,所以我就留下了它作为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`只接受2个参数。相反,你可能需要这样做
```
(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` 包装器。)