【发布时间】:2015-06-07 06:27:56
【问题描述】:
我不明白为什么下面的代码会产生反射警告:
(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"
【问题讨论】:
-
当我运行
macroexpand-1行时,我看不到类型提示。但是,我认为宏有问题;它不接受文字字符串:(my-macro "foo") ;=> java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IObj. -
您应该会看到类型提示。您确定将
*print-meta*设置为true?