如何更新 Clojure 记录的字段

How to update fields of a Clojure record

我有这个记录:

(defrecord Point [x y z])
(def location (Point. 1 2 3))

现在我想基于 location 创建一个新变量 new-location,但 z 坐标已更改。我知道我可以手动复制所有字段,即 (def new-location (Point. (:x location) (:y location) 99)),但是是否有一种更简单的方法来在功能上仅更新 Clojure 记录的几个字段?

请注意,我正在寻找一个不可变的解决方案。 是关于变异的,因此没有回答我的问题。

你只需要 assoc:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(defrecord Point [x y z])
(dotest
  (newline)
  (def p1 (->Point 1 2 3))
  (spyx p1)
  (spyx (type p1))

  (newline)
  (def p2 (assoc p1 :z 99))
  (spyx p2)
  (spyx (type p2))

  (newline)
  (def m2 (into {} p1 ))
  (spyx m2)
  (spyx (type m2))

  (newline)
  (def m3 (dissoc p1 :z ))
  (spyx m3)
  (spyx (type m3))

  (newline)
  (def m4 (assoc p1 :extra 42 ))
  (spyx m4)
  (spyx (type m4))

)


结果

-----------------------------------
   Clojure 1.10.3    Java 15.0.2
-----------------------------------

Testing tst.demo.core

p1 => #tst.demo.core.Point{:x 1, :y 2, :z 3}
(type p1) => tst.demo.core.Point

p2 => #tst.demo.core.Point{:x 1, :y 2, :z 99}
(type p2) => tst.demo.core.Point

m2 => {:x 1, :y 2, :z 3}
(type m2) => clojure.lang.PersistentArrayMap

m3 => {:x 1, :y 2}
(type m3) => clojure.lang.PersistentArrayMap

m4 => #tst.demo.core.Point{:x 1, :y 2, :z 3, :extra 42}
(type m4) => tst.demo.core.Point


请注意,简单的 assoc 将结果保留为同一类型的记录。一些操作会创建地图结果,正如我们看到的 dissoc 创建 m3.

但是,使用 assoc 添加 :extra 字段以创建 m4 会将类型保留为 Point 记录。惊喜,惊喜!

my favorite template project.

构建