为什么Clojure有5种方法来定义一个类而不是一个?

Sal*_*lil 81 clojure clojure-java-interop

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

Rob*_*lan 87

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

  1. jvm的特定类型系统
  2. 在定义类型时,需要对不同用例略有不同的语义
  3. 事实上,随着语言的发展,其中一些是早期开发的,有些是后来开发的.

首先,让我们考虑一下这些是做什么的. deftype和gen-class类似,因为它们都定义了一个用于提前编译的命名类.Gen-class排在第一位,然后是clojure 1.2中的deftype.Deftype是优选的,并且具有更好的性能特征,但是更具限制性.deftype类可以符合接口,但不能从其他类继承.

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

这就留下了为什么deftype和defrecord都出现的问题,因为它们同时出现,并且具有类似的作用.在大多数情况下,我们会想要使用defrecord:它具有我们所知道和喜爱的各种各样的clojure善良,sequability等等.Deftype旨在用作实现其他数据结构的低级构建块.它不包括常规的clojure接口,但它确实有可变字段的选项(虽然这不是默认的).

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

clojure.org数据类型页面

引入了deftype和reify的google组线程

  • @Trylks:将对象视为一系列键值对的能力.几乎所有clojure原生的东西都可以被视为一个非常强大的序列. (2认同)

mik*_*era 50

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

如果你不需要任何Java互操作,那么99%的时候你最好坚持使用defrecord或简单的Clojure映射.

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

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

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

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

  • 差异并不大,但就你想要达到的目标而言,它们在哲学上是不同的*.我认为Clojure中的多种方法反映了这些潜在的差异,这是为什么它们应该被赋予不同名称的一个很好的理由. (4认同)
  • 非常感谢流程图的链接。该博客的作者是 O'reilly 的《Programming Clojure》一书,这一点很有帮助。我认为这个决策是相当复杂的。接口和具体类之间的差异,或者是否需要定义静态方法,或者命名类型或匿名类型之间的差异是否如此巨大,以至于它们需要不同的语言构造? (2认同)