我在执行宏来执行一些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];
}
答案 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反射来使字段参数动态化。