【发布时间】:2011-10-31 19:58:52
【问题描述】:
Clojure 具有 gen-class、reify、proxy 以及 deftype 和 defrecord 来定义新的类类数据类型。对于一种重视语法简单性并厌恶不必要的复杂性的语言来说,这似乎是一种反常。 有人可以解释为什么会这样吗? Common Lisp 风格的 defclass 就够了吗?
【问题讨论】:
标签: clojure clojure-java-interop
Clojure 具有 gen-class、reify、proxy 以及 deftype 和 defrecord 来定义新的类类数据类型。对于一种重视语法简单性并厌恶不必要的复杂性的语言来说,这似乎是一种反常。 有人可以解释为什么会这样吗? Common Lisp 风格的 defclass 就够了吗?
【问题讨论】:
标签: clojure clojure-java-interop
简短的回答是,它们都有不同且有用的目的。复杂性是由于需要与底层 JVM 的不同功能进行有效的互操作。
如果您不需要任何 Java 互操作,那么在 99% 的情况下,您最好还是坚持使用 defrecord 或简单的 Clojure 映射。
如果您的需求更复杂,那么下面的流程图是一个很好的工具,可以解释为什么您会选择其中一个选项而不是其他选项:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/
【讨论】:
这是三个不同因素的混合:
首先,让我们考虑一下它们的作用。 deftype 和 gen-class 的相似之处在于它们都为提前编译定义了一个命名类。 clojure 1.2 中首先出现的是 Gen-class,然后是 deftype。 Deftype 是首选,具有更好的性能特征,但限制更多。 deftype 类可以符合一个接口,但不能从另一个类继承。
Reify 和 proxy 都用于在运行时动态创建匿名类的实例。 Proxy 最先出现,reify 与 clojure 1.2 中的 deftype 和 defrecord 一起出现。 Reify 是首选,就像 deftype 一样,语义不是太严格。
这就留下了为什么 deftype 和 defrecord 的问题,因为它们同时出现,并且具有相似的作用。对于大多数目的,我们会想要使用 defrecord:它具有我们所知道和喜爱的所有各种 clojure 优点、可排序性等等。 Deftype 旨在用作实现其他数据结构的低级构建块。它不包括常规的 clojure 接口,但它确实具有可变字段的选项(尽管这不是默认值)。
如需进一步阅读,请查看:
The clojure.org datatypes page
The google group thread where deftype and reify were introduced
【讨论】:
proxy 有时是首选,因为它允许在运行时修改方法。 (例如,The Joy of Clojure,第 2 版。建议这对于修改 Web 处理程序中的回调可能很方便。)