我的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的参数是直接从marco的args构造的,当生成的fn的params不能直接构造时会引发异常。
举个例子:
宏params
的{{1}}现在变成了这样:
defapihandler
在宏中,我想像这样动态地构建生成的fn的参数:
[{:key :username :checker [not-nil?]} {:key :password :checkers [is-secure?]} ...]
(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"}
块中构造body
块中使用的变量,然后抛出以下异常:
let
Caused by java.lang.IllegalArgumentException
Don't know how to create ISeq from: clojure.lang.Symbol
macroexpand
得到了这个:
create-user
我怀疑这个异常与let destructuring表单中使用的动态var有关,如果我的怀疑是正确的,那么如何构造(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))))
块中使用的变量?
答案 0 :(得分:3)
您需要从生成的代码中提取构建params-key向量的子句。
所以:
(defmacro defapihandler [handler-name params & body]
(let [param-keys (map (comp symbol name :key) params)]
`(defn ~handler-name [passed-param#]
(let [{:keys [~@param-keys]} passed-param#]
;; some check
(do ~@body)))))
或者,如果您不需要passed-param#
:
(defmacro defapihandler [handler-name params & body]
(let [param-keys (map (comp symbol name :key) params)]
`(defn ~handler-name [{:keys [~@param-keys]}]
;; some check
(do ~@body))))