当我尝试从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)
(合格的var?唯一的区别是我完全符合函数名称WHICH EXIST,BTW) 显然我在理解Clojure defrecord宏时遗漏了一些东西,但是我觉得那个宏只是AST修饰符,所以如果我给它一个符号或某个解析为符号的东西它是同一个东西,所以我希望有人来解释我为什么正常形式有效而其他形式无效!
TIA!
答案 0 :(得分:4)
问题如下:defrecord
是一个宏,并且不评估所有参数。它们传递给宏,因此得到(symbol "rec2")
- 包含2个元素的列表:符号和字符串,而不是rec2
。您可以尝试以下操作:
(eval `(defrecord ~(symbol "rec2") ~(vec (map symbol ["f1" "f2"]))))
创建列表(defrecord rec2 [f1 f2])
,然后对其进行评估
但我不认为动态评估一些代码是个好主意。可能还有其他一些方法可以做到。