我写了一个用于创建记录的宏
(defmacro def-entity [name & value]
`(do
(defrecord ~name (vector ~@value))
))
我创建了一个实体
(def-entity p a b)
但是当我尝试创建一个具体的实例时 (def某事(p。“a”“b”)) 我收到此消息java.lang.IllegalArgumentException:找不到类user.p(repl-1:40)的匹配ctor。 所以我必须提供3个参数,像这样 (def某人(p。“a”“b”“x”)) 它把这样的值放在
中 (-> someone :a)
"b"
(-> neko :p)
nil
我似乎不明白发生了什么事?
答案 0 :(得分:5)
由于defrecord
本身就是一个宏,并且希望记录的字段作为矢量文字传递,你最好避免传递一个引用矢量的符号,并真正构造一个矢量文字作为一部分你的宏观工作:
(defmacro defentity [name & values]
`(defrecord ~name ~(vec values)))
结果是:
user=> (macroexpand-1 '(defentity p a b))
(clojure.core/defrecord p [a b])
user=> (defentity Test foo bar)
user.Test
user=> (def s (Test. "foo" "bar"))
#'user/s
user=> s
#user.Test{:foo "foo", :bar "bar"}
相比之下,您的版本会产生以下结果,它不使用矢量文字作为defrecord
的输入:
user=> (macroexpand-1 '(def-entity p a b))
(do (clojure.core/defrecord p (clojure.core/vector a b)))
事实上,我甚至无法在Clojure 1.4中使用您的版本:
user=> (def-entity w x y)
CompilerException java.lang.RuntimeException: Can't use qualified name as parameter: clojure.core/vector, compiling:(NO_SOURCE_PATH:1)
答案 1 :(得分:2)
使用[~@value]
代替(vector ~@value)
:
(defmacro def-entity [name & value]
`(do
(defrecord ~name [~@value])
))
实际上你的变体对我来说根本不起作用。 (def-entity p a b)
抛出异常。但我可以建议将(def-entity p a b)
扩展为(defrecord p (vector a b))
并将自己作为一个宏进行自我记录,并将其作为第二个参数作为字段列表。第二个参数是(vector a b)
- 它是一个包含3个元素的列表。因此它创建了包含3个字段的记录:vector,a和b。检查(:vector someone)
返回的内容。