我正在尝试生成访问对象字段的代码,但无法避免使用反射。不清楚这是否是错误或者我在哪里做错了。
(ns user.macro)
(set! *warn-on-reflection* true)
(set! *print-meta* true)
(deftype MyObj [x])
(def -obj (MyObj. :x))
(defmacro get-x [obj]
(let [sym (with-meta (gensym) {:tag MyObj})]
`(let [~sym ~obj]
(.-x ~sym))))
;; Reflection warning here
(get-x -obj)
(comment
;; Macro expanded as:
(macroexpand-1 '(get-x -obj))
#_=> (clojure.core/let [^user.macro.MyObj G__17584 -obj] (.-x ^user.macro.MyObj G__17584))
;; PROBLEM: Benchmark and decompile shows reflection:
(get-x -obj)
#_=> :x
;// Decompiling class: user/macro$fn__17604
;package user;
;
;import clojure.lang.*;
;
;public final class macro$fn__17604 extends AFunction
;{
; public static final Var const__0;
;
; public static Object invokeStatic() {
; final Object G__17603 = macro$fn__17604.const__0.getRawRoot();
; return Reflector.invokeNoArgInstanceMember(G__17603, "x", true);
; }
;
; @Override
; public Object invoke() {
; return invokeStatic();
; }
;
; static {
; const__0 = RT.var("user.macro", "-obj");
; }
;}
; Execution time mean : 67,705637 ns
; Execution time std-deviation : 7,655054 ns
; Execution time lower quantile : 60,605456 ns ( 2,5%)
; Execution time upper quantile : 79,073366 ns (97,5%)
;; Expanded code works as expected:
(clojure.core/let [^user.macro.MyObj G__17584 -obj] (.-x ^user.macro.MyObj G__17584))
#_=> :x
;// Decompiling class: user/macro$fn__17624
;package user;
;
;import user.macro.*;
;import clojure.lang.*;
;
;public final class macro$fn__17624 extends AFunction
;{
; public static final Var const__0;
;
; public static Object invokeStatic() {
; final Object G__17584 = macro$fn__17624.const__0.getRawRoot();
; return ((MyObj)G__17584).x;
; }
;
; @Override
; public Object invoke() {
; return invokeStatic();
; }
;
; static {
; const__0 = RT.var("user.macro", "-obj");
; }
;}
; Execution time mean : 5,011374 ns
; Execution time std-deviation : 0,269197 ns
; Execution time lower quantile : 4,714841 ns ( 2,5%)
; Execution time upper quantile : 5,390264 ns (97,5%)
)