欢迎!请查看关于 页面以了解更多关于如何工作的信息。
(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 中执行时发生错误。我看不出这两个调用之间的区别,并且由于显然 local-dir 的返回值是 io/file,因此它应该推断为 java.io.File。您怎么看?
println
local-dir
调查 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互操作,实际上需要返回类型提示的情况相对较少(许多程序可能没有这种情况)。
截至目前,投入有限的使用价值的努力可能不值得,但将来可能需要考虑。