我应该在哪里使用defrecord在clojure?

Zub*_*air 71 clojure

我在我的clojure程序中使用了很多地图和结构.将这些转换为defrecords有什么好处(除了表现)?

Ale*_*ler 89

我认为结构有效地被弃用,所以我根本不使用它们.

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

  • 性能
  • 生成的类有一个我可以在多方法或其他情况下打开的类型
  • 使用defrecord附近的额外宏机器,我可以获得字段验证,默认值以及我想要的任何其他内容
  • 记录可以实现任意接口或协议(映射不能)
  • 记录充当大多数用途的地图
  • keys和val以稳定(按创建)顺序返回结果

记录的一些缺点:

  • 因为记录是Java类实例(不是Clojure映射),所以没有结构共享,因此相同的记录结构可能会使用比已更改的等效映射结构更多的内存.当您"更改"记录时,还会有更多的对象创建/破坏,尽管JVM专门设计用于吃掉这种短暂的垃圾而不会出汗.
  • 如果您在开发期间更改记录,则可能需要更频繁地重新启动REPL以获取这些更改.这通常只是在狭隘的开发过程中的一个问题.
  • 许多现有的库尚未更新以支持记录(postwalk,zip,matchure等).我们已根据需要添加了此支持.

  • 我认为,使用edn等方法也更容易对地图进行序列化/反序列化。我记得回读先前序列化的记录时遇到了一些问题,因为进行反序列化的代码无法找到我定义的记录类型的已编译代码,尽管我最终还是以某种方式对其进行了排序。如果我只使用地图,我将完全避免该问题。 (2认同)

Mic*_*ohl 14

Stuart Sierra最近写了一篇关于"用Clojure 1.2解决表达式问题"的有趣文章,其中还包含一节defrecord:

http://www.ibm.com/developerworks/java/library/j-clojure-protocols/index.html#datatypes

我认为整篇文章是理解协议和记录的一个很好的起点.

  • 这是一个仅限链接的答案.它至少需要一个简要的imo. (2认同)

bmi*_*are 9

另一个主要好处是记录有一个你可以派出的类型(它的类).

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

(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"
Run Code Online (Sandbox Code Playgroud)

  • @Goran,适用于多方法,使用协议,你只能在类型上调度.无论如何,我的观点是使用defrecords隐式添加类型,而defstruct或map不会自动添加类型. (6认同)
  • 事实并非如此,因为您可以分派任何函数,而不仅仅是类型。您可以使用普通的映射,并添加另一个带有名为“type”的键的条目。然后您可以使用调度函数来检查“type”条目的值。 (2认同)