Clojure:使用 assoc-in 的结果不一致

标签 clojure

有人可以使用 (assoc-in) 解释以下结果背后的原因吗? ?

(assoc-in {:foo {:bar {:baz "hello"}}} [:foo :bar] "world")
=> {:foo {:bar "world"}}

(assoc-in {:foo {:bar nil}} [:foo :bar :baz] "world")
=> {:foo {:bar {:baz "world"}}}

(assoc-in {:foo {:bar "hello"}} [:foo :bar :baz] "world")
=> ClassCastException java.lang.String cannot be cast to clojure.lang.Associative  clojure.lang.RT.assoc (RT.java:702)

显然我可以替换 map 甚至 nil使用另一种数据类型(例如字符串),但我不能用映射替换数据类型(例如字符串),因为它需要该数据类型已经是映射。

人们将如何解决这个问题?我想实现以下目标:
(assoc-in {:foo {:bar "hello"}} [:foo :bar :baz] "world")
=> {:foo {:bar {:baz "world"}}}

最佳答案

assoc-in assoc 之上实现.您可以替换 map 和nil因为 assoc对它们起作用:

(assoc {} :foo :bar)  ;=> {:foo :bar}
(assoc nil :foo :bar) ;=> {:foo :bar}

但是assoc不适用于字符串:
(assoc "string" :foo :bar) ;=> ClassCastException

顺便说一句,the definitionassoc-in很优雅:
(defn assoc-in
  ;; metadata elided
  [m [k & ks] v]
  (if ks
    (assoc m k (assoc-in (get m k) ks v))
    (assoc m k v)))

如果您需要替换 assoc 的值不能被调用,您需要在更浅的一层上操作并替换整个 map 而不仅仅是值:
(assoc-in {:foo {:bar "hello"}} [:foo :bar] {:baz "world"})
;=> {:foo {:bar {:baz "world"}}}

如果 map 中还有其他值您不想通过替换整个内容而丢失,您可以使用 update-in assoc :
(update-in {:foo {:bar "hello"}} [:foo] assoc :baz "hi")
;=> {:foo {:bar "hello", :baz "hi"}}

关于Clojure:使用 assoc-in 的结果不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19692764/

相关文章:

machine-learning - 垃圾邮件分类器 Clojure

clojure - 在数据中建模多个多对多关系

java - 如何在 Clojure 中实现具有具体类型参数的接口(interface)?

emacs - 为什么 REPL 将 clojure.core/doc 视为 var?

clojure - 如何找出两个数据集的差异?

clojure - 使用 Om,从嵌套映射生成嵌套 div

clojure - Clojure 有像 Mathematica 的 % 这样的功能吗?

clojure - 尝试处理 Datomic 模式时出现 "Unable to resolve entity"错误

java - 环境变量 CLASSPATH <> Clojure 的 CLASSPATH。为什么?

clojure - 嵌套循环语句