87

Clojure 具有 gen-class、reify、proxy 以及 deftype 和 defrecord 来定义新的类类数据类型。对于一种重视语法简单性并厌恶不必要的复杂性的语言来说,这似乎是一种反常。有人可以解释为什么会这样吗?Common Lisp 风格的 defclass 就足够了吗?

4

2 回答 2

94

这是三个不同因素的混合:

  1. jvm的特定类型系统
  2. 定义类型时,不同用例需要稍微不同的语义
  3. 事实上,随着语言的发展,其中一些是较早开发的,有些是较晚开发的。

所以首先,让我们考虑一下这些是做什么的。 deftypegen-class的相似之处在于它们都为提前编译定义了一个命名类。clojure 1.2 中首先出现的是 Gen-class,然后是 deftype。Deftype 是首选,具有更好的性能特征,但限制更多。deftype 类可以符合一个接口,但不能从另一个类继承。

Reify代理都用于在运行时动态创建匿名类的实例。Proxy 最先出现,reify 与 clojure 1.2 中的 deftype 和 defrecord 一起出现。Reify 是首选,就像 deftype 一样,语义不是太严格。

这就留下了为什么 deftype 和 defrecord 的问题,因为它们同时出现,并且具有相似的作用。对于大多数目的,我们会想要使用 defrecord:它具有我们所知道和喜爱的所有各种 clojure 优点、可排序性等等。Deftype 旨在用作实现其他数据结构的低级构建块。它不包括常规的 clojure 接口,但它确实具有可变字段的选项(尽管这不是默认值)。

如需进一步阅读,请查看:

clojure.org 数据类型页面

引入 deftype 和 reify 的 google 组线程

于 2011-08-22T03:20:54.223 回答
55

简短的回答是,它们都有不同且有用的目的。复杂性是由于需要与底层 JVM 的不同功能进行有效的互操作。

如果您不需要任何 Java 互操作,那么在 99% 的情况下,您最好还是坚持使用 defrecord 或简单的 Clojure 映射。

  • 如果要使用协议,请使用 defrecord
  • 否则,常规的 Clojure 映射可能是最简单且最容易理解的

如果您的需求更复杂,那么下面的流程图是一个很好的工具,可以解释为什么您会选择其中一个选项而不是其他选项:

http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/

选择正确的 clojure 类型定义表单的流程图

于 2011-08-22T09:34:01.677 回答