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

为什么Clojure有5种定义类的方法而不是一种?,clojure,clojure-java-interop,Clojure,Clojure Java Interop,Clojure有gen类、reify、proxy以及deftype和defrecord来定义像数据类型这样的新类。对于一种重视句法简单、厌恶不必要的复杂性的语言来说,这似乎是一种反常现象。 有人能解释一下为什么会这样吗?普通的Lisp风格的defclass就足够了吗?这是三个不同因素的组合: jvm的特定类型系统 定义类型时,对于不同用例需要稍微不同的语义 事实上,随着语言的发展,其中一些发展得更早,一些发展得更晚 所以首先,让我们考虑一下它们是怎么做的。strong>deftype和gen c

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

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

  • jvm的特定类型系统
  • 定义类型时,对于不同用例需要稍微不同的语义
  • 事实上,随着语言的发展,其中一些发展得更早,一些发展得更晚
  • 所以首先,让我们考虑一下它们是怎么做的。strong>deftype和gen class的相似之处在于它们都为提前编译定义了一个命名类。在clojure 1.2中,Gen类排在第一位,deftype紧随其后。Deftype是首选,具有更好的性能特征,但限制性更强。deftype类可以符合接口,但不能从另一个类继承

    具体化代理都用于在运行时动态创建匿名类的实例。在clojure 1.2中,Proxy首先出现,reify与deftype和defrecord一起出现。具体化是首选的,就像deftype一样,语义没有太多限制

    这就留下了一个问题,为什么deftype和defrecord两者同时出现,并且具有相似的作用。在大多数情况下,我们都希望使用defrecord:它具有我们所知道和喜爱的各种clojure优点、可继承性等等。Deftype旨在用作实现其他数据结构的底层构建块。它不包括常规clojure接口,但它有可变字段选项(尽管这不是默认值)

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


    简而言之,它们都有不同的用途。复杂性是由于需要与底层JVM的不同功能进行有效的互操作

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

    • 如果要使用协议,请使用defrecord
    • 否则,常规Clojure映射可能是最简单、最容易理解的
    如果您的需求更复杂,那么下面的流程图是一个很好的工具,可以解释为什么您会选择其中一个选项而不是其他选项:


    google group线程非常有价值。我的理解是,对于java互操作代理,gen类主要被reify和deftype取代。我很高兴我们现在有更少的“推荐”方法来定义类型。@Trylks:将对象视为键值对序列的能力。clojure原生的几乎所有内容都可以被视为序列,这非常强大。
    proxy
    有时是首选,因为它允许在运行时修改方法。(例如,Clojure的喜悦,第二版。建议这对于修改web处理程序中的回调可能很方便。)非常感谢链接到流程图。该博客由O'reilly的《编程Clojure》的合著者撰写,这很有帮助。我认为这个决策相当复杂。接口和具体类之间的差异,或者是否需要定义静态方法,或者命名类型或匿名类型之间的差异是如此之大,以至于它们需要不同的语言构造?这些差异不是很大,但就您试图实现的目标而言,它们在哲学上是不同的。我认为Clojure中的多种方法反映了这些潜在的差异,这就是为什么应该给它们取不同名称的一个很好的原因。流程图很好,但没有涵盖使用一个或另一个选项或它们的组合的所有可能性或原因。没有一个简单的图表可以。