防止if表达式的假分支中的宏扩展

时间:2013-04-02 08:24:25

标签: macros clojure expansion

在Clojure中,不评估与条件不匹配的if表达式的分支,因此在评估以下表达式时不会抛出异常:

=> (if nil (/ 1 0))
nil

但是,在评估if之前,宏仍会展开,因此您仍然可以获得如下例外:

=> (if nil (proxy [nil] []))
CompilerException java.lang.NullPointerException, compiling:(NO_SOURCE_PATH:1)

我正在编写一个宏,其中接口的名称有时会作为arg提供,在这种情况下,宏将生成调用proxy的代码。其他时候,界面arg将是nil,然后宏扩展为类似(if nil (proxy [nil] [])的内容,因此我得到了上述异常。 SSCE将是:

=> (defmacro make-listener [listener-name & methods]
     `(if ~listener-name
        (proxy [~listener-name] []
          ~@(map (fn [m] `(~m [e#])) methods))))
#'user/make-listener
=> (make-listener java.awt.event.ActionListener actionPerformed)
#<Object$ActionListener$46793e3a user.proxy$java.lang.Object$ActionListener$46793e3a@ed5b2>
=> (make-listener nil)
CompilerException java.lang.NullPointerException, compiling:(NO_SOURCE_PATH:1) 

如何在没有提供接口arg的情况下以不抛出异常的方式编写宏?

1 个答案:

答案 0 :(得分:4)

如果listener-name为nil那么宏应该什么都不做,即你需要在宏扩展时检查listener-name(而不是在宏发出的代码中)。

(defmacro make-listener [listener-name & methods]
  (if listener-name
     `(proxy [~listener-name] []
       ~@(map (fn [m] `(~m [e#])) methods))))