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 前缀使用语法引号,则不会有警告。

我认为我已经尝试了语法引用的变体……但实际上它真的起作用了。
谢谢。
...