简体   繁体   English

Clojure 的 defrecord - 如何使用它?

[英]Clojure's defrecord - how to use it?

I'm attempting to create my own immutable datatype/methods with defrecord in Clojure.我正在尝试使用 Clojure 中的defrecord创建我自己的不可变数据类型/方法。 The goal is to have a datatype that I can create instances of, and then call its methods to return a new copy of itself with mutated variables.目标是拥有一个我可以创建实例的数据类型,然后调用它的方法来返回一个带有变异变量的新副本。 Say a and b are vectors.假设 a 和 b 是向量。 I'd like to update a value in both and return a new copy of the entire structure with those vectors updated.我想更新两个值并返回更新了这些向量的整个结构的新副本。 This obviously doesn't compile, I'm just trying to get my ideas across.这显然不能编译,我只是想表达我的想法。

(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
  )
)

I'd like to call the constructor and then the mutator as many times as I'd like (there are other functions that don't mutate, but I don't want to make it more complex for the question).我想根据需要多次调用构造函数,然后调用 mutator(还有其他函数不会发生变异,但我不想让问题变得更复杂)。

Alternatively, if this is not idiomatic Clojure, how are you supposed to do something like this?或者,如果这不是惯用的 Clojure,您应该如何做这样的事情?

Here's how you define your record:以下是您定义记录的方式:

(defrecord MyType [a b])

Note that in Clojure you don't typically define "methods" within your record type itself (the exception is if you want to directly implement a Java interface or a protocol).请注意,在 Clojure 中,您通常不会在记录类型本身中定义“方法”(如果您想直接实现 Java 接口或协议,则例外)。

A basic constructor (prefixed with -> ) gets generated automatically for free:免费自动生成基本构造函数(以->为前缀):

(def foo (->MyType [1 2 3] [4 5 6]))

foo
=> #user.MyType{:a [1 2 3], :b [4 5 6]}

You can then write more sophisticated constructor functions that use this, eg然后您可以编写更复杂的构造函数来使用它,例如

(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]}

And "mutate-and-return" also comes for free - you can just use assoc :而且“mutate-and-return”也是免费的——你可以只使用assoc

(assoc foo :b [7 8 9])
=> user.MyType{:a [1 2 3], :b [7 8 9]}

Clojure defrecord example: Clojure 取消记录示例:

;;define Address record ;;定义地址记录

(defrecord Address [city state])

;;define Person record ;;定义人员记录

(defrecord Person [firstname lastname ^Address address])

;;buid the constructor ;;构建构造函数

(defn make-person ([fname lname city state]
               (->Person fname lname (->Address city state))))

;;create a person ;;创建一个人

(def person1 (make-person "John" "Doe" "LA" "CA"))

;;retrieve values ;;检索值

(:firstname person1)
(:city (:address person1))

Clojure allows you to create records, which are custom, maplike data types. Clojure 允许您创建记录,这些记录是自定义的、类似地图的数据类型。 They're maplike in that they associate keys with values, you can look up their values the same way you can with maps, and they're immutable like maps.它们类似于地图,因为它们将键与值相关联,您可以像使用地图一样查找它们的值,并且它们像地图一样不可变。


(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}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM