将类型提示附加到Clojure延迟呼叫

时间:2012-06-04 20:35:48

标签: clojure

我正在尝试在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.

这样做的正确方法是什么?

2 个答案:

答案 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