在Clojure宏中使用绑定的空指针异常

时间:2011-11-16 22:27:56

标签: clojure

我在执行宏来执行一些Java互操作时遇到空指针异常,我无法弄清楚原因。

我正在使用带有嵌套数据的地图设置Java对象的字段,并且因为地图键的名称与对象的字段名称相同,所以我创建了一个宏:

(defmacro set-keys! [pose m k klst]
  `(set! (. ~pose ~(symbol (name k)))
         (double-array (map #(% (~(keyword (name k)) ~m)) ~klst))))

为了进行测试,我将pse定义为初始化的Java对象,将感兴趣的字段设置为零,并将mp定义为仍然有效的简化映射:

(def mp {:pos {:x 1 :y 2})

现在出现奇怪的行为。使用显式类型参数执行set-keys!有效:

user> (set-keys! pse mp :pos [:x :y])
#<double[] [D@691ba57a>

但是,如果我使用let调用内部运行代码:

user> (let [x :pos y [:x :y]]
        (set-keys! pse mp x y))

我得到一个“无消息”的空指针异常。作为消息。这是什么问题?

编辑:我用pse定义(def pse (pose_t.))pose_t是生成的类,pose_t()构造函数初始化其字段中的所有数组,但不初始化价值。简化示例的类代码的相关行是:

public double pos[];

public pose_t() {
    pos = new double[3];
}

1 个答案:

答案 0 :(得分:3)

不评估宏参数,因此~(keyword (name k))扩展为 - 大致 - (keyword (name (quote x))) - 这是:x,not:pos

至少我猜这是问题所在。如果没有,那么如果你可以包含pse的定义那就太好了。

附录:您可以通过评估来检查宏实际扩展到的内容:

user> (macroexpand-1 '(set-keys! pse mp x y))
(set! (. pse x) (clojure.core/double-array (clojure.core/map
    (fn* [p1__2066__2067__auto__] (p1__2066__2067__auto__ (:x mp))) y)))

注意:x

附录2:(. obj field)实际上也没有评估field,这意味着您必须使用java反射来使字段参数动态化。