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
by
已选中 by
 
最佳答案

^ 读取器不解析符号,并接受符号和字符串作为标签 (实现)。
因此,编译器只查看符号和字符串 (实现)。

话虽如此,如果你用语法引号在{:tag MyObj}前加MyObj,则不会出现警告。

我还以为我已经尝试了带有语法引号的变体...但实际上它真的起作用了。
谢谢。
...