如何在 clojure 中添加类型提示来修复 "ctor can't be resolved" 反射警告,即调用构造函数?

How can I add a typehint in clojure to fix "ctor can't be resolved" reflection warning, i.e call to a constructor?

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

(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 {})))

除非您出于某种原因确实需要消除所有反射,否则最简单的答案是将此行放在您的 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)
在读取和评估以下行之前执行以禁用警告。

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

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