2016-12-24 117 views
0

我Clojure的应用程序需要一些处理做生意,这些处理器将瓶坯一些常用的参数检查,所以我使用宏来做到这一点象下面这样:如何做出正确的FN ARGS当创建FN使用宏

(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 [email protected]) 
     (-> (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无法直接构建时引发。

拿一个例子:

宏观defapihandlerparams现在成了这个样子:

[{: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 [email protected])))) 


(defapihandler create-user [{:key :username :checkers []}] 
    (println username)) 

passed-param的结构看起来像这样:{:username "foo" :password "bar"}

现在我要构建letbody块中使用的变量,那么下面的异常被抛出:

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)))) 

我怀疑这异常有关动态变量用于让解构形式,如果我的嫌疑人是正确的,那么如何构造body块中使用的变量?

回答

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 [[email protected]]} passed-param#] 
     ;; some check 
     (do [email protected]))))) 

或者,如果你不需要passed-param#

(defmacro defapihandler [handler-name params & body] 
    (let [param-keys (map (comp symbol name :key) params)] 
    `(defn ~handler-name [{:keys [[email protected]]}] 
     ;; some check 
     (do [email protected])))) 
+0

你的代码做的工作,但我仍然很困惑为什么要使用'[]'从字面上看,我的代码将尝试将'param-keys#'作为'Symbol'解析为'Symbol'而不是'ISeq',如异常所述 –

+0

参数向量或'let'子句左侧的符号未解析。例如,'(let [x'a,x 2] x)'。在这里,“x”将首先设置为符号“a”,然后“x”将设置为“2”。你不会发现'x'是'a','a'是'2'。 – weavejester