[编辑:如何在这个网站上正确地格式化代码?我试了,但无法解决这个问题,所以我就把它当作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`包装器。)