我正在尝试在Clojure中使用defrecord
创建自己的不可变数据类型/方法。目标是拥有一个我可以创建实例的数据类型,然后调用其方法以返回带有变异变量的自身的新副本。说a和b是向量。我想更新两者中的值并返回整个结构的新副本,并更新这些向量。这显然无法编译,我只是试图了解我的想法。
(defrecord MyType [a b]
(constructor [N]
; I'd like to build an initial instance, creating a and b as vectors of length N
)
(mutate-and-return []
; I'd like to mutate (assoc the vectors) and return the new structure, a and b modified
)
)
我想按照我的意愿多次调用构造函数然后调用mutator(还有其他函数不会变异,但我不想让问题变得更复杂)。
或者,如果这不是惯用的Clojure,你应该怎么做这样的事情呢?
答案 0 :(得分:30)
以下是您定义记录的方式:
(defrecord MyType [a b])
请注意,在Clojure中,您通常不会在记录类型本身中定义“方法”(例外情况是您希望直接实现Java接口或协议)。
基本构造函数(以->
为前缀)会自动生成:
(def foo (->MyType [1 2 3] [4 5 6]))
foo
=> #user.MyType{:a [1 2 3], :b [4 5 6]}
然后,您可以编写使用此功能的更复杂的构造函数,例如
(defn mytype-with-length [n]
(let [a (vec (range n))
b (vec (range n))]
(->MyType a b)))
(mytype-with-length 3)
=> #user.MyType{:a [0 1 2], :b [0 1 2]}
“mutate-and-return”也是免费的 - 你可以使用assoc:
(assoc foo :b [7 8 9])
=> user.MyType{:a [1 2 3], :b [7 8 9]}
答案 1 :(得分:5)
Clojure defrecord示例:
;;定义地址记录
(defrecord Address [city state])
;;定义人物记录
(defrecord Person [firstname lastname ^Address address])
;; buid构造函数
(defn make-person ([fname lname city state]
(->Person fname lname (->Address city state))))
;;创建一个人
(def person1 (make-person "John" "Doe" "LA" "CA"))
;;检索值
(:firstname person1)
(:city (:address person1))
答案 2 :(得分:0)
Clojure允许您创建记录,这些记录是自定义的,类似地图的数据类型。 它们就像地图一样,它们将键与值相关联,您可以像使用地图一样查找它们的值,并且它们像地图一样是不可变的。
(defrecord Person [last first address])
;=> core.Person
(defrecord Ad [street city zip])
;=> core.Ad
(def p1 (Person. "Jhon" "Mick"
(Ad. "US187956" "NY" 3369)))
;=> #'core/p1
(update-in p1 [:address :zip] inc)
;=> #core.Person{:last "Jhon", :first "Mick", :address #playsync.core.Ad{:street "US187956", :city "NY", :zip 3370}}
(assoc p1 :last "Adam")
;=> #core.Person{:last "Adam", :first "Mick", :address #playsync.core.Ad{:street "US187956", :city "NY", :zip 3370}}