Clojure 具有 gen-class、reify、proxy 以及 deftype 和 defrecord 来定义新的类类数据类型。对于一种重视语法简单性并厌恶不必要的复杂性的语言来说,这似乎是一种反常。有人可以解释为什么会这样吗?Common Lisp 风格的 defclass 就足够了吗?
2 回答
这是三个不同因素的混合:
- jvm的特定类型系统
- 定义类型时,不同用例需要稍微不同的语义
- 事实上,随着语言的发展,其中一些是较早开发的,有些是较晚开发的。
所以首先,让我们考虑一下这些是做什么的。 deftype和gen-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 接口,但它确实具有可变字段的选项(尽管这不是默认值)。
如需进一步阅读,请查看:
简短的回答是,它们都有不同且有用的目的。复杂性是由于需要与底层 JVM 的不同功能进行有效的互操作。
如果您不需要任何 Java 互操作,那么在 99% 的情况下,您最好还是坚持使用 defrecord 或简单的 Clojure 映射。
- 如果要使用协议,请使用 defrecord
- 否则,常规的 Clojure 映射可能是最简单且最容易理解的
如果您的需求更复杂,那么下面的流程图是一个很好的工具,可以解释为什么您会选择其中一个选项而不是其他选项:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/