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

标签 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显示生成的代码确实有类型提示,如果我手动编写相同的代码而不使用宏,则没有反射警告:

(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"

最佳答案

标签应该是一个符号,而不是一个类。所以下面的代码有效:

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

这实际上在 documentation of special forms 中有说明:

:tag

a symbol naming a class or a Class object that indicates the Java type of the object in the var, or its return value if the object is a fn.



事实macroexpand-1显示了一个无效的类型提示,但看起来与正确的完全一样,这非常具有误导性:)

关于clojure - Clojure 宏生成的代码中的反射警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30690706/

相关文章:

clojure - Lamson 适合 clojure?

clojure - 在 Clojure 中使用平面文件作为数据存储和引用作为表?

automation - 应用程序不接受击键

java - 自主地同时更改 JPanel 的组件

clojure - 对类名的解析感到困惑

clojure - 如何最好地与 Clojure 抽象集成?

c++ - 替换预处理器定义中的字符

templates - 模板和宏中的类型化 vs 非类型化 vs expr vs stmt

macros - Clojure -- 调度宏很特别吗?

netbeans - 在 Netbeans 上激活文本编辑宏