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` 函数或对变量和函数添加额外的包装器。
(~/clojure)-(!2001)-> clj
    Clojure 1.12.0-alpha4
    user=> (System/getProperty "java.version")
    "20.0.1"
    user=> (set! *warn-on-reflection* true)
    true
    user=> (def x 1000)
    #'user/x
    user=> (Thread/sleep x)
     Reflection warning, NO_SOURCE_PATH:1:1 - call to static method sleep on java.lang.Thread can't be resolved (argument types: unknown).
    nil
    user=>
在这种情况下,应该发生的是调用应该继续工作,但以反射的方式,如果你在意的话,可以用 ^long 类型提示进行更正。然而,在 Reflector 中存在一个微妙的错误,它从不将较小的boxed数值参数匹配为传递给接受更宽原始参数的方法的有效参数。

在这里,如果你在运行时传递一个boxed Integer,Thread.sleep() 就不会匹配到任何方法。值得注意的是,当 Cheshire 读取范围在整数范围内的 JSON 值时,它会发出boxed Integer对象(关于这个问题,Cheshire 中有一个任务)。

结合这些情况,我们看到的结果是,如果使用 Cheshire(或可能以 Integer 作为 Integer 读取配置文件的此类其他行为)并升级到较新的 Java,可能会导致运行时的反射错误,而不是弃用。这似乎是不可以接受的,因此我们提交了https://clojure.atlassian.net/browse/CLJ-2843。并在 Clojure 1.11.3 和 1.12.0-alpha10 中修复了这个问题。

1 回答

+1 点赞
在core.async中有一个与Thread/sleep类似的可移植函数。
如果你只需要休眠,那么引入整个core.async似乎有些过度。
...