我应该在Clojure的哪里使用defrecord?


74

我在clojure程序中使用了许多映射和结构。将这些转换为defrecord有什么好处(除了性能之外)?

Answers:


93

我认为结构已被弃用,因此我完全不使用它们。

当我在许多地图实例中使用一组固定的知名键时,通常会创建一条记录。最大的好处是:

  • 性能
  • 生成的类的类型可以在多种方法或其他情况下打开
  • 借助围绕defrecord的其他宏机制,我可以获取字段验证,默认值以及我想要的其他任何东西
  • 记录可以实现任意接口或协议(无法映射)
  • 记录可用作大多数用途的地图
  • 键和值以稳定(按创建)顺序返回结果

记录的一些缺点:

  • 由于记录是Java类实例(不是Clojure映射),因此没有结构共享,因此相同的记录结构将比已更改的等效映射结构使用更多的内存。尽管您“更改”一条记录,但是对象创建/销毁的对象也更多了,尽管JVM是专门为吃掉这种短暂的垃圾而设计的,而且不费吹灰之力。
  • 如果在开发过程中更改记录,则可能需要更频繁地重新启动REPL才能获取这些更改。在狭窄的开发阶段,这通常只是一个问题。
  • 许多现有的库尚未更新以支持记录(postwalk,zip,matchure等)。我们已根据需要添加了此支持。

您在第三个参数中描述的构造函数形式是Common Lisp所谓的“ BOA构造函数”-按参数的顺序使用,在用定义的Concert类型中使用defstruct。请参阅lispworks.com/documentation/HyperSpec/Body/…
seh

嗨,Alex,您好,我想您会发现记录实际上在内部使用了结构共享-它们实现了完整的持久数据结构,因此保留了常规地图的所有优点。
mikera 2011年

Mikera-一条记录会生成一个带有最终字段的Java类。关联必须生成一个新的Java对象。它可以重用字段实例,因为它们是不可变的,但效率不如普通Clojure映射。
Alex Miller

您指的是defrecord2?我找不到它,也找不到核心,也没有贡献。
Petr Gladkikh

3
我认为,例如使用edn,映射也更易于序列化/反序列化。我记得回读先前已序列化的记录时遇到了一些问题,因为进行反序列化的代码无法找到我定义的记录类型的已编译代码,尽管我最终以某种方式对其进行了排序。如果我只使用地图,我将完全避免该问题。
鲁尔'16


11

另一个主要好处是记录具有可以分派的类型(其类)。

以下是使用此功能但不能代表所有可能用途的示例:

(defprotocol communicate
  (verbalize [this]))

(defrecord Cat [hunger-level]
  communicate
  (verbalize [this]
    (apply str (interpose " " (repeat hunger-level "meow")))))

(defrecord Dog [mood]
  communicate
  (verbalize [this]
    (case mood
      :happy "woof"
      "arf")))

(verbalize (->Cat 3))
; => "meow meow meow"

(verbalize (->Dog :happy))
; => "woof"

1
并非如此,因为您可以分派任何函数,而不仅仅是类型。您可以使用普通地图,例如,添加另一个名为“ type”的项。然后,您可以使用调度功能来检查“类型”条目的值。
Goran Jovic

6
@Goran,适用于多方法,使用协议,只能按类型分派。无论如何,我的观点是使用defrecords隐式添加类型,而defstruct或map不会自动添加类型。
bmillare 2011年

这个答案确实很简洁,可能有一个很好的例子。
matanster,

添加了一个示例
bmillare

2

在大多数情况下,使用地图,仅在需要多态时才记录。单独使用地图,您仍然可以使用多种方法。但是,如果需要协议,则需要记录。鉴于此,请等到需要协议后再诉诸记录。在此之前,请避免使用它们,而希望使用更多以数据为中心和更简单的代码。


1

除了前面提到的内容外,记录在性能上通常处于同等水平或更高,并且在公开与映射相同的编程接口时,记录还采用了温和的结构:在执行时,键名和键数是强制的定义。这对于避免从许多值期望相同的结构(或否则只是人为地僵硬的)避免愚蠢的错误可能很有用。

无论最初的动机是什么,此属性都将其与地图区分开。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.