在Clojure中,我应该在哪里使用defrecord?

75

我在我的Clojure程序中使用了许多地图(maps)和结构体(structs)。除了性能以外,将它们转换为defrecords的好处是什么?

5个回答

95

我认为结构体已经被有效地淘汰了,因此我根本不使用它们。

当我有一个在许多映射实例中使用的固定的众所周知的键集时,我通常创建一个记录。其主要好处是:

  • 性能
  • 生成的类具有我可以在多方法或其他情况下切换的类型
  • 通过defrecord周围的附加宏机器,我可以获得字段验证、默认值和任何其他东西
  • 记录可以实现任意接口或协议(映射不能)
  • 对于大多数目的,记录可作为映射
  • keys和vals以稳定(每次创建)的顺序返回结果

一些记录的缺点:

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

嗨,Alex - 我认为你会发现记录实际上在底层使用结构共享 - 它们实现了完整的持久数据结构,因此它们保留了常规映射的所有优点。 - mikera
那么基本上,当我在面向对象编程中使用类时,在Clojure中我会使用记录吗?(考虑到字段验证等非常重要的因素,与不安全的地图相比)。 - User
是的,记录被设计为代表“信息实体”,这与面向对象中的领域对象相当匹配。 - Alex Miller
3
我认为使用诸如edn之类的工具对地图进行序列化和反序列化也更容易。我曾经遇到过读取以前序列化的记录的问题,因为进行反序列化的代码无法找到我定义的记录类型的已编译代码,尽管最终我设法解决了这个问题。如果我只使用地图,我完全可以避免这个问题。 - Rulle
@AlexMiller 这里留下了关于性能和无结构共享的矛盾观点,让人感到困惑。除非记录中有超过几个元素,否则它为什么会影响性能呢? - matanster
显示剩余4条评论

14

3
这是一个仅包含链接的回答。我认为它需要至少一个摘要。 - MasterMastic

13

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

使用此功能的示例但并不代表所有可能的用法如下:

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

2
并不是,因为您可以对任何函数进行调度,而不仅仅是类型。 您可以使用普通的映射表,比如添加另一个键为“type”的条目。 然后,您可以使用一个调度函数来检查“type”条目的值。 - Goran Jovic
6
@Goran,这适用于多方法,使用协议时,只能根据类型进行分派。无论如何,我的观点是使用defrecords隐式地添加了一个类型,而defstruct或map并不会自动添加类型。 - bmillare
这个回答非常简洁,加入一个例子可能会更好。 - matanster
添加了一个示例。 - bmillare

4

在大多数情况下,使用map即可,只有需要多态时才使用记录。仅使用地图仍然可以使用多方法;但是,如果您想要协议,则需要记录。因此,在诉诸记录之前,请等待需要协议。在那之前,避免使用它们,而应优先考虑更加数据中心化和简单的代码。


2
除了之前提到的内容外,除了通常表现出色或优越的性能,并且公开与地图相同的编程接口之外,记录还强制执行轻微结构:键名和键数在定义时得到强制执行。这可能有助于避免期望从许多值中获得相同结构(否则只是人为刻板)而导致的愚蠢错误。
无论最初的动机是什么,这个属性也使它不同于地图。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接