如何在 clojure 中添加类型提示以修复“无法解析ctor”反射警告,即调用构造函数?

时间:2021-01-12 00:33:25

标签: clojure clojure-java-interop

以下示例函数使用 Clojure 的 Java 互操作的特殊形式调用类构造函数,导致反射警告:

(defn test-reflection-err []
  (new java.util.HashMap {}))

该消息内容如下:

Reflection warning, /Users/ethan/Projects/scicloj/tablecloth.time/src/tablecloth/time/index.clj:26:3 - call to java.util.HashMap ctor can't be resolved.

我尝试放置类型提示来避免这种情况,但不确定将它们放置在哪里以防止反射错误。有人知道怎么做吗?

我试过了:

(defn test-reflection-err []
  (^TreeMap new java.util.HashMap {}))

(defn test-reflection-err []
  (doto ^TreeMap (new java.util.HashMap {})))

2 个答案:

答案 0 :(得分:5)

您需要在构造函数参数中添加一个提示:

(let [^java.util.Map m {}]
  (new java.util.HashMap m))

答案 1 :(得分:-2)

除非您出于某种原因确实需要消除所有反射,否则最简单的答案是将此行放在您的 project.clj 中:

:global-vars {*warn-on-reflection* false}

在使用空的 Clojure 映射作为构造函数 arg 时,我无法获得消除警告的类型提示。观察此代码:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(dotest
  (newline)
  (spyxx {:a 1}) ; `spyxx` prints expression, type, and value

  (newline)
  (spyxx (java.util.HashMap.))     ; Works
  (spyxx (new java.util.HashMap))  ; Works

  (newline)
  (let [m ^java.util.Map {}]
    (spyxx (new java.util.HashMap m))  ; Reflection Warning
    (spyxx (java.util.HashMap. m)))    ; Reflection Warning

  (newline)
  (let [^java.util.Map m {}]
    (spyxx (new java.util.HashMap m))  ; Works
    (spyxx (java.util.HashMap. m))))   ; Works

(def ^java.util.Map m3 {})
(dotest
  (newline)
  (spyxx m3)
  (spyxx (java.util.HashMap. m3))) ; Works

结果如下。请注意,它们都可以工作,但是您会在上面指出的地方收到反射警告:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 15
--------------------------------------

Testing tst.demo.core

{:a 1} => <#clojure.lang.PersistentArrayMap {:a 1}>

(java.util.HashMap.)     => <#java.util.HashMap {}>
(new java.util.HashMap)  => <#java.util.HashMap {}>

(new java.util.HashMap m)  => <#java.util.HashMap {}>
(java.util.HashMap. m)     => <#java.util.HashMap {}>

(new java.util.HashMap m)  => <#java.util.HashMap {}>
(java.util.HashMap. m)     => <#java.util.HashMap {}>

m3 => <#clojure.lang.PersistentArrayMap {}>
(java.util.HashMap. m3)   => <#java.util.HashMap {}>

看来您不需要空的 Clojure 映射作为构造函数 arg,然后问题就消失了。您还可以通过将 *warn-on-reflection* 设置为 false(在 project.clj 中或在代码中手动设置)来消除警告。

如果你使用类型提示,很容易把它放在错误的地方,它会被默默地忽略。


更新

考虑这个额外的代码:

(dotest
  (newline)
  (set! *warn-on-reflection* false) ; not executed upon parsing
  (let [m4 ^java.util.Map {}]
    (spyxx (new java.util.HashMap m4)) ; Reflection Warning
    (spyxx (java.util.HashMap. m4))))  ; Reflection Warning

(newline)
; vvv executed when parsed before following lines
(set! *warn-on-reflection* false)
(let [m5 ^java.util.Map {}]
  (spyxx (new java.util.HashMap m5))  ; Works
  (spyxx (java.util.HashMap. m5)))    ; Works

第一个测试在解析时(在测试运行之前)会生成一个反射警告,因为解析器似乎正在评估常量表达式(推测)。

第二个测试不会产生警告,因为 Clojure 正在依次读取、解析和评估每个表单。因此调用 (set! *warn-on-reflection* false)
在读取和评估以下行之前执行以禁用警告。