为什么 Clojure 有 5 种定义类的方法而不是只有一种?
Clojure 具有 gen-class、reify、proxy 以及 deftype 和 defrecord 来定义新的类数据类型。对于一种重视语法简单性并厌恶不必要的复杂性的语言来说,这似乎是一种畸变。 有人可以解释为什么会这样吗? Common Lisp 风格的 defclass 就足够了吗?
Clojure has gen-class, reify, proxy and also deftype and defrecord to define new class-like datatypes. For a language that values syntactic simplicity and abhors unnecessary complexity, it seems like an aberration.
Could someone explain why it is so? Could Common Lisp-style defclass have sufficed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是三个不同因素的混合:
首先,让我们考虑一下它们的作用。 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 接口,但它确实具有可变字段的选项(尽管这不是默认值)。
如需进一步阅读,请查看:
clojure.org 数据类型页面
引入 deftype 和 reify 的 Google 群组线程
This is a mix of three different factors:
So first, let's consider what these do. deftype and gen-class are similar in that they both define a named class for ahead-of-time compilation. Gen-class came first, followed by deftype in clojure 1.2. Deftype is preferred, and has better performance characteristics, but is more restrictive. A deftype class can conform to an interface, but cannot inherit from another class.
Reify and proxy are both used to dynamically create an instance of an anonymous class at runtime. Proxy came first, reify came along with deftype and defrecord in clojure 1.2. Reify is preferred, just as deftype is, where the semantics are not too restrictive.
That leaves the question of why both deftype and defrecord, since they appeared at the same time, and have a similar role. For most purposes, we will want to use defrecord: it has all the various clojure goodness that we know and love, sequability and so forth. Deftype is intended for use as a low level building block for the implementation of other datastructures. It doesn't include the regular clojure interfaces, but it does have the option of mutable fields (though this isn't the default).
For further reading check out:
The clojure.org datatypes page
The google group thread where deftype and reify were introduced
简而言之,它们都有不同且有用的目的。其复杂性是由于需要与底层 JVM 的不同功能进行有效的互操作。
如果您不需要任何 Java 互操作,那么 99% 的情况下您最好坚持使用 defrecord 或简单的 Clojure 映射。
如果您的需求更复杂,那么以下流程图是一个很好的工具,用于解释为什么您会选择这些选项之一而不是其他选项:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/
The short answer is that they all have different and useful purposes. The complexity is due to the need to interoperate effectively with different features of the underlying JVM.
If you don't need any Java interop then 99% of the time you are best off sticking with either defrecord or a simple Clojure map.
If your needs are more complex, then the following flowchart is a great tool for explaining why you would choose one of these options over the others:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/