为什么在 def 中 '@foo Cons 的 class 而不是 PersistentList?

Why is the class of '@foo Cons rather than PersistentList when inside a def?

Clojure repl 下的快速实验:

> (class '@foo)
clojure.lang.PersistentList

这或多或少是预料之中的,所以让我们将相同的表达式包装在 def:

> (def x '@foo)
> (class x)
clojure.lang.Cons

我试过 def 和其他各种形式,但 '@foo 似乎是唯一触发此行为的形式。

我在一个新的 REPL 中尝试了这个并重现了这个行为。

对于您所看到的特定行为,有一个令人费解的解释。您在 Clojure reader.

中发现了一个奇特的角落

@ 字符是一个“reader 宏”,即 shorthand 以下内容:

@xxx  =>  (deref xxx)

' 字符是另一个 reader 宏,也是 shorthand 用于:

'yyy  => (quote yyy)

把它们放在一起你就得到了

'@zzz  =>  (quote (deref zzz))

所以 quote 特殊形式排在第一位。它说,“将此处包含的所有内容视为数据结构,而不是可执行代码”。

数据结构(deref zzz)是一个包含2个符号的列表,derefzzz


关于class字面量和Var的区别,我们看到:

user=> (def bbb '@foo)
#'user/bbb
user=> (class bbb)
clojure.lang.Cons

user=> (def ccc (quote (deref foo)))
#'user/ccc
user=> (class ccc)
clojure.lang.PersistentList

使用“面向对象”的术语,ConsPersistentListPersistentVectorLazySeq 都是泛型的“sub类” Clojure 中的“Seq”类型。它们都可以互换使用,上面2类中意想不到的区别是一个不重要的实现细节。