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

欢迎!请参阅关于页面以了解此页面如何工作的更多信息。

+16
Clojure
编辑

从JDK19+开始,以下内容无需添加类型提示即可实现反射

(def x 10)
(Thread/sleep x)

复杂之处在于,在较早期的JDK中,上述内容不进行反射,但当您升级JDK时,反射才开始。

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

有一个接受的数字的内置睡眠函数会很好,这样我们就不需要忘记添加类型提示,并且它们在各种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"
    user=> (set! *warn-on-reflection* true)
    true
    user=> (def x 1000)
    #'user/x
    user=> (Thread/sleep x)
     反射警告,NO_SOURCE_PATH:1:1 - 无法解析调用静态方法 sleep on java.lang.Thread (参数类型:未知)。
    null
    user=>
在此情况下,“正常”的操作应该是该方法应以反射性方式继续工作,但如果你关心,可以使用 ^long 类型提示来纠正。然而,在 Reflector 中存在一个细微的缺陷,它从不将较小的有包装数值参数视为可以作为参数传递给接收较宽原始参数的方法的有效匹配项。

在这里,如果你在运行时传递一个有包装的 Integer,它将不会为 Thread.sleep() 匹配任何方法。还有一个有用的信息是,Cheshire 会在读取 JSON 时发出有包装的 Integer 对象,如果值在整数范围内(有关此事在 Cheshire 中有一个工单)。

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

1 个答案

+1
by
在core.async中有一个Thread/sleep的便携式类似物。
by
不过,如果你只需睡眠,而全部的核心异步库都似乎是过度的。
...