【发布时间】:2016-12-24 11:46:44
【问题描述】:
我的 Clojure 应用需要一些处理程序来处理业务,这些处理程序会执行一些常见的参数检查,所以我使用宏来执行此操作,如下所示:
(defmacro defapihandler [handler-name params & body]
`(defn ~handler-name ~params
(let [keyed-params# (map keyword '~params)
checked-ret# (check-param (zipmap keyed-params# ~params))]
(if (:is-ok checked-ret#)
(do ~@body)
(-> (response {:code 10000
:msg (format " %s are missing !!!" (:missed-params checked-ret#))})
(status 400))))))
然后我可以像这样使用上面的宏:
(defapihandler create-user [username password birthday]
;; todo
)
这样一切都很好。
如您所见,生成的 fn 的参数是直接从宏的 args 构造的,当生成的 fn 的参数不能直接构造时会引发异常。
举个例子:
宏defapihandler的params现在变成了这样:
[{:key :username :checker [not-nil?]} {:key :password :checkers [is-secure?]} ...]
在宏中,我想像这样动态构建生成的 fn 的参数:
(defmacro defapihandler [handler-name params & body]
`(defn ~handler-name [passed-param#]
(let [param-keys# (vec (map (comp symbol name :key)
~params))
{:keys param-keys#} passed-param#]
;; some check
(do ~@body))))
(defapihandler create-user [{:key :username :checkers []}]
(println username))
passed-param 的结构如下:{:username "foo" :password "bar"}
现在我想在let块中构造body块中使用的变量,然后抛出以下异常:
Caused by java.lang.IllegalArgumentException
Don't know how to create ISeq from: clojure.lang.Symbol
macroexpandcreate-user 得到这个:
(defn create-user [passed-param__10243__auto__]
(let [param-keys__10244__auto__ (vec
(map
(comp symbol name :key)
[{:key :username,
:checkers []}]))
{:keys param-keys__10244__auto__} passed-param__10243__auto__]
(do (println username))))
我怀疑这个异常与let解构形式中使用的动态var有关,如果我的怀疑是正确的,那么如何构造body块中使用的变量?
【问题讨论】: