我正在尝试在Java对象上放置句柄,这些句柄在编译时不可用,但在运行时可用,如下所示:
(def component-manager (delay (SomeJavaObject/getHandle)))
(如果有比延迟更好的机制,欢迎这样做。)
使用这些对象时,会生成反射警告。因为有时这些是相当频繁的,我试图通过以下方式避免它:
(def my-handle ^SomeJavaObject (delay (SomeJavaObject/getHandle)))
不幸的是,在这种情况下仍会生成反射警告。
修改引用有效:
(.foo ^SomeJavaObject @my-handle)
...但这会大大增加代码。
在一个添加类型提示的宏中包装似乎是一种显而易见的方法:
(def my-handle' (delay (SomeJavaObject/getHandle)))
(defmacro my-handle []
(with-meta '(deref my-handle')
{:tag SomeJavaObject}))
......看起来它应该做正确的事情:
=> (set! *print-meta* true)
=> (macroexpand '(my-handle))
^SomeJavaObject (deref my-handle')
...但是当橡胶碰到道路时,这并不成立:
=> (.foo (my-handle))
Reflection warning, NO_SOURCE_PATH:1 - reference to field foo can't be resolved.
这样做的正确方法是什么?
答案 0 :(得分:3)
我不确定延迟是否是最好的事情,或者可以有更好的解决方案来管理这些Java对象,但就下面的反射警告而言,代码确实通过在一个函数中包含延迟值访问来解决它提示。
user=> (set! *warn-on-reflection* true)
true
user=> (def myobj (delay "hello world"))
#'user/myobj
user=> (defn ^String get-my-obj [] @myobj)
#'user/get-my-obj
user=> (.length (get-my-obj))
11
为了使您更容易创建一个创建延迟对象的宏,并创建一个get-<delay object name>
函数来使用类型提示来访问该延迟对象。
答案 1 :(得分:2)
我想提供两种不同的解决方案:
<强> 1。延迟强>
首先,我想发布一个答案,说明如何重新创建问题。 (如同措辞,你的问题是抽象的,不能在REPL中运行。)
(set! *warn-on-reflection* true)
(def rt (delay (Runtime/getRuntime)))
(.availableProcessors @rt) ; Reflection warning
你提到你不喜欢以下方法,因为你认为它很详细:
(.availableProcessors ^java.lang.Runtime @rt) ; no warning
我尝试了以下操作,但它没有解决反射警告:
(def rt (delay ^java.lang.Runtime (Runtime/getRuntime)))
(.availableProcessors @rt) ; Reflection warning
结论:如果您想使用延迟,Ankur's answer效果很好。为了使其适应这个例子:
(def delayed-runtime (delay (Runtime/getRuntime)))
(defn ^java.lang.Runtime get-runtime [] @delayed-runtime)
(.availableProcessors (get-runtime)) ; no warning
<强> 2。 memoize的强>
您也可以考虑使用memoization,因为它需要更少的代码:
(def ^java.lang.Runtime get-runtime (memoize #(Runtime/getRuntime)))
(.availableProcessors (get-runtime)) ; no warning