7

我有一些 Clojure 代码试图通过几层 Java 代码进行互操作(在这种情况下,java.nio.Path通过java.nio.file.WatchEvent<?>

(defn unroll-event
  [^WatchEvent event]
  { :kind (.kind event)
    :context (.context event)
    :path (-> event .context .toAbsolutePath .toString)})

在这段代码中,我输入了 hinted event,所以我认为它应该能够弄清楚.context应该返回什么,因此能够弄清楚什么.toAbsolutePath.toString做什么。我认为在这种情况下,由于.contextis defined 返回了一个泛型类型T,我想知道是否可以键入提示调用.context. 我已经尝试分别在^java.nio.file.Pathto .context、 and^Path^Stringto.toAbsolutePath和之前添加toString,但我仍然收到警告:

Reflection warning, junkcode/core.clj:28 - reference to field toAbsolutePath can't be resolved.
Reflection warning, junkcode/core.clj:28 - reference to field toString can't be resolved.

在这种情况下我能做些什么吗?是因为它->是一个宏并且其中有用于类型提示的特殊规则吗?

4

2 回答 2

3

(-> x .blah ^String .bar)基本上,扩展为 ,(^String .bar (.blah x))这显然不是您想要提示的地方。关键是类型提示在任何上下文(例如宏)中都没有特殊行为:它只是应用于源代码符号的元数据。在您的示例->中,没有任何地方可以将元数据放在输入表单上,这会导致它在输出表单中出现在您想要的位置。所以你需要写一些其他的形式,比如(-> ^Path (.context event) .toAbsolutePath str),例如。

此外,Clojure 的推理器对泛型类型一无所知,因此方法返回 T 被视为方法返回对象,这解释了为什么您需要在这里提示。

于 2012-10-07T06:07:16.727 回答
3

我不知道这是否一直如此,但在 Clojure 1.4.0、1.5.1 和 1.6.0 中,->只要使用括号,就可以随时输入提示:

user=> (set! *warn-on-reflection* true)
true
user=> (fn [^java.nio.file.WatchEvent e] 
         (-> e ^java.nio.file.Path .context .toAbsolutePath))
Reflection warning, /private/var/folders/9_/wdph6m796zzc8trzcbtcmhrn5bjpt0/T/form-init8364673644863044068.clj:1:35 - reference to field toAbsolutePath on java.lang.Object can't be resolved.
#<user$eval1995$fn__1996 user$eval1995$fn__1996@8128f39>
user=> ; but no warning if we do
user=> (fn [^java.nio.file.WatchEvent e]
         (-> e ^java.nio.file.Path (.context) .toAbsolutePath))
#<user$eval1999$fn__2000 user$eval1999$fn__2000@4747e32a>

唯一的区别是周围的括号.context

于 2014-06-12T19:11:27.177 回答