【问题标题】:Why should update be preferred over assoc?为什么更新优先于关联?
【发布时间】:2022-11-30 00:38:38
【问题描述】:

在 clojure 中,要编辑映射键的值,有 2 个选项可用:

  1. update
  2. assoc

    我可以从 clojure 文档中找到的唯一区别是 update 函数执行以下额外操作:

    如果键不存在,则 nil 作为旧值传递。

    除此以外,是否有任何我应该使用更新或关联的特定用例?

    或者在哪些情况下我应该更喜欢什么(如果我错过了这些用例)。

【问题讨论】:

    标签: functional-programming clojure


    【解决方案1】:

    如果使用得当,它们都会在您的代码中明确说明意图:

    • assoc 提示读者,新的添加 kv 对(或 替换现有键的值)并且它们往往不是 依赖于该键的当前值。
    • update 提示,键的一个值得到更新,原始值 值(如果存在)可用于此计算。
    (update {} :a (fnil inc 0))
    ; → {:a 1}
    (update {:a 41} :a (fnil inc 0))
    ; → {:a 42}
    (assoc {:z 0} :a 42 :b 23}
    ; → {:z 0, :a 42, :b 23}
    

    【讨论】:

      【解决方案2】:

      你用assoc模拟update如下

      (assoc m :foo (f (:foo m)))
      

      看起来很笨重,最好是:

      (update m :foo f)
      

      它返回一个新映射,f 应用于与 :foo 键对应的值。

      【讨论】:

      • 这实际上是update的实现方式
      • 这不仅笨重,而且对于 m 的值效果不佳,这些值计算起来很昂贵或有副作用。如果您需要更新键的值并且您关心以前的值,update 是可行的方法。
      • @amalloy 因为update被实现为(defn update [m k f] (assoc m k (f (get m k)))),为什么是OP的版本对于计算成本高或有副作用的 m 值效果不佳get 比使用关键字作为函数更好吗?
      • @Thumbnail 我说的是(assoc (expensive-map) k (f (get (expensive-map) k)))(update (expensive-map) k f) 之间的区别。因为 update 是一个函数,所以它的参数自然只会被求值一次。但是如果你使用assoc,你必须走得更远以避免重复评估地图。
      猜你喜欢
      • 2014-05-14
      • 2011-12-13
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 2014-01-12
      • 2014-01-17
      • 2012-12-29
      相关资源
      最近更新 更多