Clojure宏生成的代码中的反射警告

时间:2015-06-07 06:27:57

标签: clojure macros

我不明白为什么以下代码会产生反射警告:

(set! *warn-on-reflection* true)

(defmacro my-macro [k] `(.length ~(with-meta k {:tag String})))

(defn my-fun1 [k] (my-macro k))
;; Reflection warning, /tmp/form-init2370243866132870536.clj:1:18 - reference to field length can't be resolved.

使用macroexpand-1表示生成的代码确实具有typehint,如果我在不使用宏的情况下手动编写相同的代码,则没有反射警告:

(set! *print-meta* true)

(macroexpand-1 '(my-macro k))
;; (.length ^java.lang.String k)

(defn my-fun2 [k] (.length ^String k))
;; All good, no reflection warning

对该功能进行基准测试表明该警告不仅仅是一个红色鲱鱼,反射实际上是在运行时发生的:

(time (reduce + (map my-fun1 (repeat 1000000 "test"))))
;; "Elapsed time: 3080.252792 msecs"

(time (reduce + (map my-fun2 (repeat 1000000 "test"))))
;; "Elapsed time: 275.204877 msecs"

1 个答案:

答案 0 :(得分:3)

标签应该是符号,而不是类。所以下面的代码可以工作:

(defmacro my-macro [k] `(.length ~(with-meta k {:tag `String})))

这实际上在documentation of special forms

中说明
  

:标签

     

命名类或类对象的符号,表示Java   var中对象的类型,如果对象是a,则返回值   FN。

macroexpand-1显示类型提示无效但看起来与正确类型提示完全相同的事实是非常误导的:)