欢迎!请参阅 关于 页面以了解如何使用本网站的一些更多信息。
(ns graalvm-list-issue.main (:require [clojure.java.io :as io]) (:gen-class)) (defn- home-path [] (System/getProperty "user.home")) (defn- local-dir [] (io/file (home-path) ".local")) (defn -main [& _args] (println (seq (.list (io/file (home-path) ".local")))) (println (seq (.list (local-dir)))))
(完整代码见此处: https://github.com/conao3/clojure-graalvm-list-issue)
第一行的 println 没有反射,第二行的 println 有反射,并且在 GraalVM 运行时发生错误。我看不到这两个调用的区别,并且由于显然 io/file 是 local-dir 的返回值,它应该推断为 java.io.File 类型。您认为呢?
println
io/file
local-dir
java.io.File
研究 Clojure 源代码
关键函数是 hasJavaClass 和 getJavaClass。 https://github.com/clojure/clojure/blob/8c8e4f6ef21f3d0f59deb60cdc7e1b584f596d59/src/jvm/clojure/lang/Compiler.java#L359-L361
hasJavaClass
getJavaClass
FnExpr: https://github.com/clojure/clojure/blob/8c8e4f6ef21f3d0f59deb60cdc7e1b584f596d59/src/jvm/clojure/lang/Compiler.java#L4450-L4454
InvokeExpr: https://github.com/clojure/clojure/blob/8c8e4f6ef21f3d0f59deb60cdc7e1b584f596d59/src/jvm/clojure/lang/Compiler.java#L4286-L4290
local-dir 实际上返回 Object,就像 Clojure 中没有返回类型提示的所有函数一样。这里没有进行推断。
Object
您可以将其提示为返回 File: (defn- local-dir ^java.io.File [] ..)
File
(defn- local-dir ^java.io.File [] ..)
那么您就不会得到反射。
虽然在这个例子中这似乎很简单,但是一旦引入条件语句/多个尾部位置和原始数据类型,事情就会变得相当复杂。在存在多个尾部位置的上下文中,答案可能实际上是多个答案——在这种情况下,你可能需要找到一个共同的超类型或省略。
此外,由于类型提示主要用于 Java 交互,因此真正需要返回类型提示的情况相对较少(许多程序可能没有此类情况)。
目前,生产有限用途所需的努力可能不值得,但未来可能值得一看。