2

当我尝试从 REPL 运行以下代码时(使用动态记录):

(defrecord (symbol "rec2") (vec (map symbol ["f1" "f2"])))

我收到错误CompilerException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:23)

我问自己我在哪里生成这个 PersistentList 考虑到:

user=> (symbol "rec2")
rec2
user=> (vec (map symbol ["f1" "f2"]))
[f1 f2]

但我真正的问题是为什么以下代码有效:

user=> (defrecord rec2 [f1 f2])
user.rec2

我也试过:

user=> (clojure.core/defrecord (clojure.core/symbol "rec1") (vec (clojure.core/map clojure.core/symbol ["f1" "f2"])))
CompilerException java.lang.RuntimeException: Can't refer to qualified var that doesn't exist, compiling:(NO_SOURCE_PATH:40)

(qualified var?唯一的区别是我完全限定了函数名 WHICH EXIST, BTW) 显然我在理解 Clojure defrecord 宏时遗漏了一些东西,但我认为宏只是 AST 修饰符,所以如果我给它一个符号或解析为符号的东西是同一件事,所以我想有人解释一下为什么正常形式有效而其他形式无效!

蒂亚!

4

1 回答 1

4

问题如下:defrecord是一个宏,所有参数都没有被评估。他们传递给宏,所以它得到(symbol "rec2")- 包含 2 个元素的列表:符号和字符串,而不是rec2您期望的。您可以尝试以下操作:

(eval `(defrecord ~(symbol "rec2") ~(vec (map symbol ["f1" "f2"])))) 

它创建列表(defrecord rec2 [f1 f2]),然后对其进行评估。
但我不认为动态评估一些代码是个好主意。可能还有其他方法可以做到这一点。

于 2012-06-14T09:53:52.723 回答