代码之家  ›  专栏  ›  技术社区  ›  missingfaktor Kevin Wright

为什么要在下面的代码中得到NPE?

  •  7
  • missingfaktor Kevin Wright  · 技术社区  · 16 年前

    下面的代码按预期执行,但给出了一个 NullPointerException

    (ns my-first-macro)
    
    (defmacro exec-all [& commands]
      (map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands))
    
    (exec-all
      (cons 2 [4 5 6])
      ({:k 3 :m 8} :k)
      (conj [4 5 \d] \e \f))
    
    ; Output:
    ; Clojure 1.2.0-master-SNAPSHOT
    ; Code:  (cons 2 [4 5 6])   =>  Result:  (2 4 5 6)
    ; Code:  ({:k 3, :m 8} :k)  =>  Result:  3
    ; Code:  (conj [4 5 d] e f)     =>  Result:  [4 5 d e f]
    ; java.lang.NullPointerException (MyFirstMacro.clj:0)
    ; 1:1 user=> #<Namespace my-first-macro>
    ; 1:2 my-first-macro=> 
    

    (对于正确语法突出显示的代码,请转到 here .)

    2 回复  |  直到 16 年前
        1
  •  11
  •   mikera    16 年前

    看看正在发生的扩张:

    (macroexpand '(exec-all (cons 2 [4 5 6])))
    =>
    ((clojure.core/println "Code: " (quote (cons 2 [4 5 6])) "\t=>\tResult: " (cons 2 [4 5 6])))
    

    为了解决这个问题,我建议修改宏,在前面加一个“do”,例如。

    (defmacro exec-all [& commands]
      (cons 'do (map (fn [c] `(println "Code: " '~c "\t=>\tResult: " ~c)) commands)))
    
        2
  •  6
  •   Michał Marczyk    16 年前

    (defmacro exec-all [& commands]
      `(doseq [c# ~(vec (map (fn [c]
                               `(fn [] (println "Code: " '~c "=> Result: " ~c)))
                             commands))]
         (c#)))
    

    这扩展到

    (doseq [c [(fn []
                 (println "Code: "      '(conj [2 3 4] 5)
                          "=> Result: " (conj [2 3 4] 5)))
               (fn []
                 (println "Code: "      '(+ 1 2)
                          "=> Result: " (+ 1 2)))]]
      (c))
    

    fn c 在宏展开时收集在向量中。

    (do ...)

    互动示例:

    user=> (exec-all (conj [2 3 4] 5) (+ 1 2))                                                                                                    
    Code:  (conj [2 3 4] 5) => Result:  [2 3 4 5]
    Code:  (+ 1 2) => Result:  3
    nil