2024 Clojure状态调查中分享您的想法!

欢迎!请访问关于页面以获取更多有关此功能的信息。

+16
Clojure
编辑

从JDK19+开始,以下代码不需要添加类型提示即可进行反射

(def x 10)
(Thread/sleep x)

棘手的是,在较早期的JDK中上述代码不会触发反射,但当您升级JDK后,反射开始启动。

如果您使用native-image,由于缺少反射配置,程序可能开始失败。

有一个内置的sleep函数能够接受数字,这样我们就不会忘记添加类型提示,并且它可以在所有的JDK上都能一致地工作就好了。

例如:

(ns clojure.java.misc)
(defn sleep [x]
  (if (number? x)
    (Thread/sleep (long x))
    ....)

clojure.java.misc的更好名字是welcome。也许简单地命名为clojure.java或者将这个函数放入clojure.core

奇怪的是,我现在无法在1.11.1和JDK 20上重现它 - 在REPL中,通过执行脚本,通过执行`-main`函数,以及围绕var和函数的额外包装。
(~/clojure)-(!2001)-> clj
    Clojure 1.12.0-alpha4
    user=> (System/getProperty "java.version")
    "20.0.1"
    用户=> (set! *warn-on-reflection* true)
    true
    用户=> (def x 1000)
    #'用户/x
    用户=> (Thread/sleep x)
     反射警告,NO_SOURCE_PATH:1:1 - 无法解析对java.lang.Thread的静态方法sleep的调用(参数类型:未知)。
    nil
    用户=>
在这种情况下,“正常”的情况应该是调用应该继续工作,但通过反射,你可以用^long类型提示进行纠正(如果你关心的话)。然而,在Reflector中存在一个微小的漏洞,它从未将较小的boxed numeric参数与本应接受更宽原始参数类型的方法相匹配。

在这里,如果在运行时传递boxed Integer,则与Thread.sleep()不匹配任何方法。值得注意的是,当读取JSON时,Cheshire会发出boxed Integer对象,如果值在整数范围内(Cheshire关于此的票证)。

结合这些情况,我们看到的后果是,如果使用Cheshire(或具有类似行为的其他东西,可能以Integer读取配置文件),并且升级到较新的Java,可能会产生运行时不是弃用错误,而是一个反射错误。这看起来是不可接受的,所以我们为Clojure 1.11.3和1.12.0-alpha10提出了https://clojure.atlassian.net/browse/CLJ-2843并修复了这个问题。

1 答案

+1
core.async中有Thread/sleep的可移植类似项。
by
如果你只需要sleep功能,那么导入整个core.async似乎太过分了。
...