请在2024 年 Clojure 状态调查中分享您的想法!

欢迎!请参阅关于页面以获取更多关于此如何工作的小信息。

0

我正在尝试生成访问对象字段的代码,但我无法避免反射。不清楚这是否是错误,或者我在做错什么。

(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%)

  )

1 个答案

+1

选择
 
最佳回答

^ 读取器不会解析符号,并接受符号和字符串作为标签(实现)。
因此,编译器除了符号和字符串之外不查看任何东西(实现)。

话虽如此,如果你在 {:tag MyObj} 中用语法引号前缀 MyObj,编译器不会发出警告。

by
我本以为我已经尝试了使用语法引号变体的方案……但它确实管用。
谢谢。
...